Merge bf9a901536d830b7caf3e1472de5ee2fd4eb0ae7 into ce8179f07e4fb8740b43570aa2c5826447c2af26
This commit is contained in:
commit
3e471bd315
1438
mev_inspect/abis/ironbank/CYEther.json
Normal file
1438
mev_inspect/abis/ironbank/CYEther.json
Normal file
File diff suppressed because it is too large
Load Diff
1438
mev_inspect/abis/ironbank/CYToken.json
Normal file
1438
mev_inspect/abis/ironbank/CYToken.json
Normal file
File diff suppressed because it is too large
Load Diff
246
mev_inspect/abis/ironbank/Unitroller.json
Normal file
246
mev_inspect/abis/ironbank/Unitroller.json
Normal file
@ -0,0 +1,246 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"inputs": [],
|
||||||
|
"payable": false,
|
||||||
|
"stateMutability": "nonpayable",
|
||||||
|
"type": "constructor"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"anonymous": false,
|
||||||
|
"inputs": [
|
||||||
|
{
|
||||||
|
"indexed": false,
|
||||||
|
"internalType": "uint256",
|
||||||
|
"name": "error",
|
||||||
|
"type": "uint256"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"indexed": false,
|
||||||
|
"internalType": "uint256",
|
||||||
|
"name": "info",
|
||||||
|
"type": "uint256"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"indexed": false,
|
||||||
|
"internalType": "uint256",
|
||||||
|
"name": "detail",
|
||||||
|
"type": "uint256"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"name": "Failure",
|
||||||
|
"type": "event"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"anonymous": false,
|
||||||
|
"inputs": [
|
||||||
|
{
|
||||||
|
"indexed": false,
|
||||||
|
"internalType": "address",
|
||||||
|
"name": "oldAdmin",
|
||||||
|
"type": "address"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"indexed": false,
|
||||||
|
"internalType": "address",
|
||||||
|
"name": "newAdmin",
|
||||||
|
"type": "address"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"name": "NewAdmin",
|
||||||
|
"type": "event"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"anonymous": false,
|
||||||
|
"inputs": [
|
||||||
|
{
|
||||||
|
"indexed": false,
|
||||||
|
"internalType": "address",
|
||||||
|
"name": "oldImplementation",
|
||||||
|
"type": "address"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"indexed": false,
|
||||||
|
"internalType": "address",
|
||||||
|
"name": "newImplementation",
|
||||||
|
"type": "address"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"name": "NewImplementation",
|
||||||
|
"type": "event"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"anonymous": false,
|
||||||
|
"inputs": [
|
||||||
|
{
|
||||||
|
"indexed": false,
|
||||||
|
"internalType": "address",
|
||||||
|
"name": "oldPendingAdmin",
|
||||||
|
"type": "address"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"indexed": false,
|
||||||
|
"internalType": "address",
|
||||||
|
"name": "newPendingAdmin",
|
||||||
|
"type": "address"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"name": "NewPendingAdmin",
|
||||||
|
"type": "event"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"anonymous": false,
|
||||||
|
"inputs": [
|
||||||
|
{
|
||||||
|
"indexed": false,
|
||||||
|
"internalType": "address",
|
||||||
|
"name": "oldPendingImplementation",
|
||||||
|
"type": "address"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"indexed": false,
|
||||||
|
"internalType": "address",
|
||||||
|
"name": "newPendingImplementation",
|
||||||
|
"type": "address"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"name": "NewPendingImplementation",
|
||||||
|
"type": "event"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"payable": true,
|
||||||
|
"stateMutability": "payable",
|
||||||
|
"type": "fallback"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"constant": false,
|
||||||
|
"inputs": [],
|
||||||
|
"name": "_acceptAdmin",
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"internalType": "uint256",
|
||||||
|
"name": "",
|
||||||
|
"type": "uint256"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"payable": false,
|
||||||
|
"stateMutability": "nonpayable",
|
||||||
|
"type": "function"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"constant": false,
|
||||||
|
"inputs": [],
|
||||||
|
"name": "_acceptImplementation",
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"internalType": "uint256",
|
||||||
|
"name": "",
|
||||||
|
"type": "uint256"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"payable": false,
|
||||||
|
"stateMutability": "nonpayable",
|
||||||
|
"type": "function"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"constant": false,
|
||||||
|
"inputs": [
|
||||||
|
{
|
||||||
|
"internalType": "address",
|
||||||
|
"name": "newPendingAdmin",
|
||||||
|
"type": "address"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"name": "_setPendingAdmin",
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"internalType": "uint256",
|
||||||
|
"name": "",
|
||||||
|
"type": "uint256"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"payable": false,
|
||||||
|
"stateMutability": "nonpayable",
|
||||||
|
"type": "function"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"constant": false,
|
||||||
|
"inputs": [
|
||||||
|
{
|
||||||
|
"internalType": "address",
|
||||||
|
"name": "newPendingImplementation",
|
||||||
|
"type": "address"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"name": "_setPendingImplementation",
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"internalType": "uint256",
|
||||||
|
"name": "",
|
||||||
|
"type": "uint256"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"payable": false,
|
||||||
|
"stateMutability": "nonpayable",
|
||||||
|
"type": "function"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"constant": true,
|
||||||
|
"inputs": [],
|
||||||
|
"name": "admin",
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"internalType": "address",
|
||||||
|
"name": "",
|
||||||
|
"type": "address"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"payable": false,
|
||||||
|
"stateMutability": "view",
|
||||||
|
"type": "function"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"constant": true,
|
||||||
|
"inputs": [],
|
||||||
|
"name": "comptrollerImplementation",
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"internalType": "address",
|
||||||
|
"name": "",
|
||||||
|
"type": "address"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"payable": false,
|
||||||
|
"stateMutability": "view",
|
||||||
|
"type": "function"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"constant": true,
|
||||||
|
"inputs": [],
|
||||||
|
"name": "pendingAdmin",
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"internalType": "address",
|
||||||
|
"name": "",
|
||||||
|
"type": "address"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"payable": false,
|
||||||
|
"stateMutability": "view",
|
||||||
|
"type": "function"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"constant": true,
|
||||||
|
"inputs": [],
|
||||||
|
"name": "pendingComptrollerImplementation",
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"internalType": "address",
|
||||||
|
"name": "",
|
||||||
|
"type": "address"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"payable": false,
|
||||||
|
"stateMutability": "view",
|
||||||
|
"type": "function"
|
||||||
|
}
|
||||||
|
]
|
@ -11,6 +11,7 @@ from .cream import CREAM_CLASSIFIER_SPECS
|
|||||||
from .cryptopunks import CRYPTOPUNKS_CLASSIFIER_SPECS
|
from .cryptopunks import CRYPTOPUNKS_CLASSIFIER_SPECS
|
||||||
from .curve import CURVE_CLASSIFIER_SPECS
|
from .curve import CURVE_CLASSIFIER_SPECS
|
||||||
from .erc20 import ERC20_CLASSIFIER_SPECS
|
from .erc20 import ERC20_CLASSIFIER_SPECS
|
||||||
|
from .ironbank import IRONBANK_CLASSIFIER_SPECS
|
||||||
from .opensea import OPENSEA_CLASSIFIER_SPECS
|
from .opensea import OPENSEA_CLASSIFIER_SPECS
|
||||||
from .uniswap import UNISWAP_CLASSIFIER_SPECS
|
from .uniswap import UNISWAP_CLASSIFIER_SPECS
|
||||||
from .weth import WETH_CLASSIFIER_SPECS
|
from .weth import WETH_CLASSIFIER_SPECS
|
||||||
@ -29,6 +30,7 @@ ALL_CLASSIFIER_SPECS = (
|
|||||||
+ CRYPTOPUNKS_CLASSIFIER_SPECS
|
+ CRYPTOPUNKS_CLASSIFIER_SPECS
|
||||||
+ OPENSEA_CLASSIFIER_SPECS
|
+ OPENSEA_CLASSIFIER_SPECS
|
||||||
+ BANCOR_CLASSIFIER_SPECS
|
+ BANCOR_CLASSIFIER_SPECS
|
||||||
|
+ IRONBANK_CLASSIFIER_SPECS
|
||||||
)
|
)
|
||||||
|
|
||||||
_SPECS_BY_ABI_NAME_AND_PROTOCOL: Dict[
|
_SPECS_BY_ABI_NAME_AND_PROTOCOL: Dict[
|
||||||
|
140
mev_inspect/classifiers/specs/ironbank.py
Normal file
140
mev_inspect/classifiers/specs/ironbank.py
Normal file
@ -0,0 +1,140 @@
|
|||||||
|
from typing import List, Optional
|
||||||
|
|
||||||
|
from mev_inspect.classifiers.helpers import get_debt_transfer, get_received_transfer
|
||||||
|
from mev_inspect.schemas.classifiers import (
|
||||||
|
Classification,
|
||||||
|
ClassifiedTrace,
|
||||||
|
ClassifierSpec,
|
||||||
|
DecodedCallTrace,
|
||||||
|
LiquidationClassifier,
|
||||||
|
SeizeClassifier,
|
||||||
|
)
|
||||||
|
from mev_inspect.schemas.liquidations import Liquidation
|
||||||
|
from mev_inspect.schemas.prices import ETH_TOKEN_ADDRESS
|
||||||
|
from mev_inspect.schemas.traces import Protocol
|
||||||
|
from mev_inspect.schemas.transfers import Transfer
|
||||||
|
|
||||||
|
CYETH_TOKEN_ADDRESS = "0x41c84c0e2ee0b740cf0d31f63f3b6f627dc6b393"
|
||||||
|
|
||||||
|
|
||||||
|
class IronBankLiquidationClassifier(LiquidationClassifier):
|
||||||
|
@staticmethod
|
||||||
|
def parse_liquidation(
|
||||||
|
liquidation_trace: DecodedCallTrace,
|
||||||
|
child_transfers: List[Transfer],
|
||||||
|
child_traces: List[ClassifiedTrace],
|
||||||
|
) -> Optional[Liquidation]:
|
||||||
|
|
||||||
|
liquidator = liquidation_trace.from_address
|
||||||
|
liquidated = liquidation_trace.inputs["borrower"]
|
||||||
|
|
||||||
|
debt_token_address = liquidation_trace.to_address
|
||||||
|
received_token_address = liquidation_trace.inputs["cTokenCollateral"]
|
||||||
|
|
||||||
|
debt_purchase_amount = None
|
||||||
|
received_amount = None
|
||||||
|
|
||||||
|
debt_purchase_amount, debt_token_address = (
|
||||||
|
(liquidation_trace.value, ETH_TOKEN_ADDRESS)
|
||||||
|
if debt_token_address == CYETH_TOKEN_ADDRESS
|
||||||
|
and liquidation_trace.value != 0
|
||||||
|
else (liquidation_trace.inputs["repayAmount"], CYETH_TOKEN_ADDRESS)
|
||||||
|
)
|
||||||
|
|
||||||
|
debt_transfer = get_debt_transfer(liquidator, child_transfers)
|
||||||
|
|
||||||
|
received_transfer = get_received_transfer(liquidator, child_transfers)
|
||||||
|
|
||||||
|
seize_trace = _get_seize_call(child_traces)
|
||||||
|
|
||||||
|
if debt_transfer is not None:
|
||||||
|
debt_token_address = debt_transfer.token_address
|
||||||
|
debt_purchase_amount = debt_transfer.amount
|
||||||
|
|
||||||
|
if received_transfer is not None:
|
||||||
|
received_token_address = received_transfer.token_address
|
||||||
|
received_amount = received_transfer.amount
|
||||||
|
|
||||||
|
elif seize_trace is not None and seize_trace.inputs is not None:
|
||||||
|
received_amount = seize_trace.inputs["seizeTokens"]
|
||||||
|
|
||||||
|
if received_amount is None:
|
||||||
|
return None
|
||||||
|
|
||||||
|
return Liquidation(
|
||||||
|
liquidated_user=liquidated,
|
||||||
|
debt_token_address=debt_token_address,
|
||||||
|
liquidator_user=liquidator,
|
||||||
|
debt_purchase_amount=debt_purchase_amount,
|
||||||
|
protocol=liquidation_trace.protocol,
|
||||||
|
received_amount=received_amount,
|
||||||
|
received_token_address=received_token_address,
|
||||||
|
transaction_hash=liquidation_trace.transaction_hash,
|
||||||
|
trace_address=liquidation_trace.trace_address,
|
||||||
|
block_number=liquidation_trace.block_number,
|
||||||
|
error=liquidation_trace.error,
|
||||||
|
)
|
||||||
|
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
IRONBANK_CYETH_SPEC = ClassifierSpec(
|
||||||
|
abi_name="CYEther",
|
||||||
|
protocol=Protocol.ironbank,
|
||||||
|
valid_contract_addresses=["0x41c84c0e2EE0b740Cf0d31F63f3B6F627DC6b393"],
|
||||||
|
classifiers={
|
||||||
|
"liquidateBorrow(address,address)": IronBankLiquidationClassifier,
|
||||||
|
"seize(address,address,uint256)": SeizeClassifier,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
IRONBANK_CTOKEN_SPEC = ClassifierSpec(
|
||||||
|
abi_name="CYToken",
|
||||||
|
protocol=Protocol.ironbank,
|
||||||
|
valid_contract_addresses=[
|
||||||
|
"0x41c84c0e2ee0b740cf0d31f63f3b6f627dc6b393", # cyWETH
|
||||||
|
"0x8e595470ed749b85c6f7669de83eae304c2ec68f", # cyDAI
|
||||||
|
"0xe7bff2da8a2f619c2586fb83938fa56ce803aa16", # cyLINK
|
||||||
|
"0xfa3472f7319477c9bfecdd66e4b948569e7621b9", # cyYFI
|
||||||
|
"0x12a9cc33a980daa74e00cc2d1a0e74c57a93d12c", # cySNX
|
||||||
|
"0x8fc8bfd80d6a9f17fb98a373023d72531792b431", # cyWBTC
|
||||||
|
"0x48759f220ed983db51fa7a8c0d2aab8f3ce4166a", # cyUSDT
|
||||||
|
"0x76eb2fe28b36b3ee97f3adae0c69606eedb2a37c", # cyUDSC
|
||||||
|
"0xa7c4054afd3dbbbf5bfe80f41862b89ea05c9806", # cySUSD
|
||||||
|
"0xa8caea564811af0e92b1e044f3edd18fa9a73e4f", # cyEURS
|
||||||
|
"0xca55f9c4e77f7b8524178583b0f7c798de17fd54", # cySEUR
|
||||||
|
"0x7736ffb07104c0c400bb0cc9a7c228452a732992", # cyDPI
|
||||||
|
"0xbddeb563e90f6cbf168a7cda4927806477e5b6c6", # cyUSDP
|
||||||
|
"0xFEEB92386A055E2eF7C2B598c872a4047a7dB59F", # cyUNI
|
||||||
|
"0x226F3738238932BA0dB2319a8117D9555446102f", # cySUSHI
|
||||||
|
"0xB8c5af54bbDCc61453144CF472A9276aE36109F9", # cyCRV
|
||||||
|
"0x30190a3B52b5AB1daF70D46D72536F5171f22340", # cyAAVE
|
||||||
|
"0x9e8E207083ffd5BDc3D99A1F32D1e6250869C1A9", # iMIM
|
||||||
|
"0xE0B57FEEd45e7D908f2d0DaCd26F113Cf26715BF", # iCVX
|
||||||
|
"0xd2b0D3594427e0c57C39e3455E2FB2dFED1e0B99", # iAPE
|
||||||
|
"0x00e5c0774A5F065c285068170b20393925C84BF3", # cyEUR
|
||||||
|
"0x3c9f5385c288cE438Ed55620938A4B967c080101", # cyKRW
|
||||||
|
"0x215F34af6557A6598DbdA9aa11cc556F5AE264B1", # cyJPY
|
||||||
|
"0x86BBD9ac8B9B44C95FFc6BAAe58E25033B7548AA", # cyAUD
|
||||||
|
"0xecaB2C76f1A8359A06fAB5fA0CEea51280A97eCF", # cyGBP
|
||||||
|
"0x1b3E95E8ECF7A7caB6c4De1b344F94865aBD12d5", # cyCHF
|
||||||
|
"0x672473908587b10e65DAB177Dbaeadcbb30BF40B", # cyZAR
|
||||||
|
],
|
||||||
|
classifiers={
|
||||||
|
"liquidateBorrow(address,uint256,address)": IronBankLiquidationClassifier,
|
||||||
|
"seize(address,address,uint256)": SeizeClassifier,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
IRONBANK_CLASSIFIER_SPECS: List[ClassifierSpec] = [
|
||||||
|
IRONBANK_CYETH_SPEC,
|
||||||
|
IRONBANK_CTOKEN_SPEC,
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
def _get_seize_call(traces: List[ClassifiedTrace]) -> Optional[ClassifiedTrace]:
|
||||||
|
"""Find the call to `seize` in the child traces (successful liquidation)"""
|
||||||
|
for trace in traces:
|
||||||
|
if trace.classification == Classification.seize:
|
||||||
|
return trace
|
||||||
|
return None
|
@ -50,6 +50,7 @@ class Protocol(Enum):
|
|||||||
cryptopunks = "cryptopunks"
|
cryptopunks = "cryptopunks"
|
||||||
bancor = "bancor"
|
bancor = "bancor"
|
||||||
opensea = "opensea"
|
opensea = "opensea"
|
||||||
|
ironbank = "ironbank"
|
||||||
|
|
||||||
|
|
||||||
class ClassifiedTrace(Trace):
|
class ClassifiedTrace(Trace):
|
||||||
|
19377
tests/blocks/14422990.json
Normal file
19377
tests/blocks/14422990.json
Normal file
File diff suppressed because one or more lines are too long
64
tests/test_ironbank.py
Normal file
64
tests/test_ironbank.py
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
from mev_inspect.classifiers.trace import TraceClassifier
|
||||||
|
from mev_inspect.liquidations import get_liquidations
|
||||||
|
from mev_inspect.schemas.liquidations import Liquidation
|
||||||
|
from mev_inspect.schemas.traces import Protocol
|
||||||
|
from tests.utils import load_test_block
|
||||||
|
|
||||||
|
# ironbank_markets = load_ironbank_markets()
|
||||||
|
|
||||||
|
|
||||||
|
# def test_cream_ether_liquidation(trace_classifier: TraceClassifier):
|
||||||
|
# block_number = 13404932
|
||||||
|
# transaction_hash = (
|
||||||
|
# "0xf5f3df6ec9b51e8e88d0d9078b04373742294530b6bcb9be045525fcab71b915"
|
||||||
|
# )
|
||||||
|
|
||||||
|
# liquidations = [
|
||||||
|
# Liquidation(
|
||||||
|
# liquidated_user="0x44f9636ef615a73688a84da1d714a40be503157d",
|
||||||
|
# liquidator_user="0x949ed86c385d191e96af136e2024d96e467d7651",
|
||||||
|
# debt_token_address=ETH_TOKEN_ADDRESS,
|
||||||
|
# debt_purchase_amount=1002704779407853614,
|
||||||
|
# received_amount=417926832636968,
|
||||||
|
# received_token_address="0x2db6c82ce72c8d7d770ba1b5f5ed0b6e075066d6",
|
||||||
|
# protocol=Protocol.cream,
|
||||||
|
# transaction_hash=transaction_hash,
|
||||||
|
# trace_address=[1, 0, 5, 1],
|
||||||
|
# block_number=block_number,
|
||||||
|
# )
|
||||||
|
# ]
|
||||||
|
# block = load_test_block(block_number)
|
||||||
|
# classified_traces = trace_classifier.classify(block.traces)
|
||||||
|
# result = get_liquidations(classified_traces)
|
||||||
|
|
||||||
|
# for liquidation in liquidations:
|
||||||
|
# assert liquidation in result
|
||||||
|
|
||||||
|
|
||||||
|
def test_ironbank_token_liquidation(trace_classifier: TraceClassifier):
|
||||||
|
block_number = 14422990
|
||||||
|
transaction_hash = (
|
||||||
|
"0xb7b6192174289b765f318d18ad8dbd2e51a55fa359fd580ffa59d9e4693a4b9f"
|
||||||
|
)
|
||||||
|
|
||||||
|
liquidations = [
|
||||||
|
Liquidation(
|
||||||
|
liquidated_user="0x1791d5ebbdfd565f136e60a3c43269b148f92b44",
|
||||||
|
liquidator_user="0x811213d2d0e26ecf65714074cef59119dd7f36d9",
|
||||||
|
debt_token_address="0xfafdf0c4c1cb09d430bf88c75d88bb46dae09967",
|
||||||
|
debt_purchase_amount=398544459931981264561,
|
||||||
|
received_amount=75246788,
|
||||||
|
received_token_address="0x8fc8bfd80d6a9f17fb98a373023d72531792b431",
|
||||||
|
protocol=Protocol.ironbank,
|
||||||
|
transaction_hash=transaction_hash,
|
||||||
|
trace_address=[0, 1, 1],
|
||||||
|
block_number=block_number,
|
||||||
|
)
|
||||||
|
]
|
||||||
|
block = load_test_block(block_number)
|
||||||
|
classified_traces = trace_classifier.classify(block.traces)
|
||||||
|
result = get_liquidations(classified_traces)
|
||||||
|
|
||||||
|
for liquidation in liquidations:
|
||||||
|
print(liquidation)
|
||||||
|
assert liquidation in result
|
Loading…
x
Reference in New Issue
Block a user