Merge pull request #74 from flashbots/aave-v0
Add AAVE liquidations to inspect_block
This commit is contained in:
commit
4834d068f6
86
mev_inspect/aave_liquidations.py
Normal file
86
mev_inspect/aave_liquidations.py
Normal file
@ -0,0 +1,86 @@
|
||||
from typing import List
|
||||
|
||||
from mev_inspect.traces import (
|
||||
get_child_traces,
|
||||
is_child_of_any_address,
|
||||
)
|
||||
from mev_inspect.schemas.classified_traces import (
|
||||
ClassifiedTrace,
|
||||
DecodedCallTrace,
|
||||
Classification,
|
||||
Protocol,
|
||||
)
|
||||
|
||||
from mev_inspect.schemas.transfers import ERC20Transfer
|
||||
from mev_inspect.schemas.liquidations import Liquidation
|
||||
|
||||
AAVE_CONTRACT_ADDRESSES: List[str] = [
|
||||
# AAVE Proxy
|
||||
"0x398ec7346dcd622edc5ae82352f02be94c62d119",
|
||||
# AAVE V2
|
||||
"0x7d2768de32b0b80b7a3454c06bdac94a69ddc7a9",
|
||||
# AAVE V1
|
||||
"0x3dfd23a6c5e8bbcfc9581d2e864a68feb6a076d3",
|
||||
# AAVE V2 WETH
|
||||
"0x030ba81f1c18d280636f32af80b9aad02cf0854e",
|
||||
# AAVE AMM Market DAI
|
||||
"0x79bE75FFC64DD58e66787E4Eae470c8a1FD08ba4",
|
||||
]
|
||||
|
||||
|
||||
def get_aave_liquidations(
|
||||
traces: List[ClassifiedTrace],
|
||||
) -> List[Liquidation]:
|
||||
|
||||
"""Inspect list of classified traces and identify liquidation"""
|
||||
liquidations: List[Liquidation] = []
|
||||
parent_liquidations: List[List[int]] = []
|
||||
|
||||
for trace in traces:
|
||||
|
||||
if (
|
||||
trace.classification == Classification.liquidate
|
||||
and isinstance(trace, DecodedCallTrace)
|
||||
and not is_child_of_any_address(trace, parent_liquidations)
|
||||
):
|
||||
|
||||
parent_liquidations.append(trace.trace_address)
|
||||
liquidator = trace.from_address
|
||||
|
||||
child_traces = get_child_traces(
|
||||
trace.transaction_hash, trace.trace_address, traces
|
||||
)
|
||||
|
||||
received_amount = _get_liquidator_payback(child_traces, liquidator)
|
||||
|
||||
liquidations.append(
|
||||
Liquidation(
|
||||
liquidated_user=trace.inputs["_user"],
|
||||
collateral_token_address=trace.inputs["_collateral"],
|
||||
debt_token_address=trace.inputs["_reserve"],
|
||||
liquidator_user=liquidator,
|
||||
debt_purchase_amount=trace.inputs["_purchaseAmount"],
|
||||
protocol=Protocol.aave,
|
||||
received_amount=received_amount,
|
||||
transaction_hash=trace.transaction_hash,
|
||||
block_number=trace.block_number,
|
||||
)
|
||||
)
|
||||
|
||||
return liquidations
|
||||
|
||||
|
||||
def _get_liquidator_payback(
|
||||
child_traces: List[ClassifiedTrace], liquidator: str
|
||||
) -> int:
|
||||
for child in child_traces:
|
||||
if child.classification == Classification.transfer:
|
||||
|
||||
child_transfer = ERC20Transfer.from_trace(child)
|
||||
|
||||
if (child_transfer.to_address == liquidator) and (
|
||||
child.from_address in AAVE_CONTRACT_ADDRESSES
|
||||
):
|
||||
return child_transfer.amount
|
||||
|
||||
return 0
|
@ -22,6 +22,7 @@ from mev_inspect.crud.transfers import delete_transfers_for_block, write_transfe
|
||||
from mev_inspect.miner_payments import get_miner_payments
|
||||
from mev_inspect.swaps import get_swaps
|
||||
from mev_inspect.transfers import get_transfers
|
||||
from mev_inspect.aave_liquidations import get_aave_liquidations
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
@ -75,6 +76,9 @@ def inspect_block(
|
||||
delete_arbitrages_for_block(db_session, block_number)
|
||||
write_arbitrages(db_session, arbitrages)
|
||||
|
||||
liquidations = get_aave_liquidations(classified_traces)
|
||||
logger.info(f"Found {len(liquidations)} liquidations")
|
||||
|
||||
miner_payments = get_miner_payments(
|
||||
block.miner, block.base_fee_per_gas, classified_traces, block.receipts
|
||||
)
|
||||
|
14
mev_inspect/schemas/liquidations.py
Normal file
14
mev_inspect/schemas/liquidations.py
Normal file
@ -0,0 +1,14 @@
|
||||
from pydantic import BaseModel
|
||||
from mev_inspect.schemas.classified_traces import Protocol
|
||||
|
||||
|
||||
class Liquidation(BaseModel):
|
||||
liquidated_user: str
|
||||
liquidator_user: str
|
||||
collateral_token_address: str
|
||||
debt_token_address: str
|
||||
debt_purchase_amount: int
|
||||
received_amount: int
|
||||
protocol: Protocol
|
||||
transaction_hash: str
|
||||
block_number: str
|
@ -34,6 +34,18 @@ def get_child_traces(
|
||||
return child_traces
|
||||
|
||||
|
||||
def is_child_of_any_address(
|
||||
trace: ClassifiedTrace, parent_trace_addresses: List[List[int]]
|
||||
) -> bool:
|
||||
|
||||
return any(
|
||||
[
|
||||
is_child_trace_address(trace.trace_address, parent)
|
||||
for parent in parent_trace_addresses
|
||||
]
|
||||
)
|
||||
|
||||
|
||||
def get_traces_by_transaction_hash(
|
||||
traces: List[ClassifiedTrace],
|
||||
) -> Dict[str, List[ClassifiedTrace]]:
|
||||
|
1
tests/blocks/10921991.json
Normal file
1
tests/blocks/10921991.json
Normal file
File diff suppressed because one or more lines are too long
1
tests/blocks/12498502.json
Normal file
1
tests/blocks/12498502.json
Normal file
File diff suppressed because one or more lines are too long
1
tests/blocks/13179291.json
Normal file
1
tests/blocks/13179291.json
Normal file
File diff suppressed because one or more lines are too long
1
tests/blocks/13244807.json
Normal file
1
tests/blocks/13244807.json
Normal file
File diff suppressed because one or more lines are too long
@ -1,23 +1,124 @@
|
||||
import unittest
|
||||
from typing import List
|
||||
|
||||
# Fails precommit because these inspectors don't exist yet
|
||||
# from mev_inspect import inspector_compound
|
||||
# from mev_inspect import inspector_aave
|
||||
#
|
||||
#
|
||||
# class TestLiquidations(unittest.TestCase):
|
||||
# def test_compound_liquidation(self):
|
||||
# tx_hash = "0x0ec6d5044a47feb3ceb647bf7ea4ffc87d09244d629eeced82ba17ec66605012"
|
||||
# block_no = 11338848
|
||||
# res = inspector_compound.get_profit(tx_hash, block_no)
|
||||
# # self.assertEqual(res['profit'], 0)
|
||||
#
|
||||
# def test_aave_liquidation(self):
|
||||
# tx_hash = "0xc8d2501d28800b1557eb64c5d0e08fd6070c15b6c04c39ca05631f641d19ffb2"
|
||||
# block_no = 10803840
|
||||
# res = inspector_aave.get_profit(tx_hash, block_no)
|
||||
# # self.assertEqual(res['profit'], 0)
|
||||
from mev_inspect.aave_liquidations import get_aave_liquidations
|
||||
from mev_inspect.schemas.liquidations import Liquidation
|
||||
from mev_inspect.schemas.classified_traces import Protocol
|
||||
from mev_inspect.classifiers.trace import TraceClassifier
|
||||
from tests.utils import load_test_block
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
def test_single_weth_liquidation():
|
||||
|
||||
transaction_hash = (
|
||||
"0xb7575eedc9d8cfe82c4a11cd1a851221f2eafb93d738301995ac7103ffe877f7"
|
||||
)
|
||||
block_number = 13244807
|
||||
|
||||
liquidations = [
|
||||
Liquidation(
|
||||
liquidated_user="0xd16404ca0a74a15e66d8ad7c925592fb02422ffe",
|
||||
liquidator_user="0x19256c009781bc2d1545db745af6dfd30c7e9cfa",
|
||||
collateral_token_address="0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2",
|
||||
debt_token_address="0xdac17f958d2ee523a2206206994597c13d831ec7",
|
||||
debt_purchase_amount=26503300291,
|
||||
received_amount=8182733924513576561,
|
||||
protocol=Protocol.aave,
|
||||
transaction_hash=transaction_hash,
|
||||
block_number=block_number,
|
||||
)
|
||||
]
|
||||
|
||||
block = load_test_block(block_number)
|
||||
trace_classifier = TraceClassifier()
|
||||
classified_traces = trace_classifier.classify(block.traces)
|
||||
result = get_aave_liquidations(classified_traces)
|
||||
|
||||
_assert_equal_list_of_liquidations(result, liquidations)
|
||||
|
||||
|
||||
def test_single_liquidation():
|
||||
|
||||
transaction_hash = (
|
||||
"0xe6c0e3ef0436cb032e1ef292141f4fc4dcd47a75a2559602133114952190e76b"
|
||||
)
|
||||
block_number = 10921991
|
||||
|
||||
liquidations = [
|
||||
Liquidation(
|
||||
liquidated_user="0x8d8d912fe4db5917da92d14fea05225b803c359c",
|
||||
liquidator_user="0xf2d9e54f0e317b8ac94825b2543908e7552fe9c7",
|
||||
collateral_token_address="0x80fb784b7ed66730e8b1dbd9820afd29931aab03",
|
||||
debt_token_address="0xdac17f958d2ee523a2206206994597c13d831ec7",
|
||||
debt_purchase_amount=1069206535,
|
||||
received_amount=2657946947610159065393,
|
||||
protocol=Protocol.aave,
|
||||
transaction_hash=transaction_hash,
|
||||
block_number=block_number,
|
||||
)
|
||||
]
|
||||
|
||||
block = load_test_block(block_number)
|
||||
trace_classifier = TraceClassifier()
|
||||
classified_traces = trace_classifier.classify(block.traces)
|
||||
result = get_aave_liquidations(classified_traces)
|
||||
|
||||
_assert_equal_list_of_liquidations(result, liquidations)
|
||||
|
||||
|
||||
def test_multiple_liquidations_in_block():
|
||||
|
||||
transaction1 = "0xedd062c3a728db4b114f2e83cac281d19a9f753e36afa8a35cdbdf1e1dd5d017"
|
||||
transaction2 = "0x18492f250cf4735bd67a21c6cc26b7d9c59cf2fb077356dc924f36bc68a810e5"
|
||||
transaction3 = "0x191b05b28ebaf460e38e90ac6a801681b500f169041ae83a45b32803ef2ec98c"
|
||||
block_number = 12498502
|
||||
|
||||
liquidation1 = Liquidation(
|
||||
liquidated_user="0x6c6541ae8a7c6a6f968124a5ff2feac8f0c7875b",
|
||||
liquidator_user="0x7185e240d8e9e2d692cbc68d30eecf965e9a7feb",
|
||||
collateral_token_address="0x514910771af9ca656af840dff83e8264ecf986ca",
|
||||
debt_token_address="0x4fabb145d64652a948d72533023f6e7a623c7c53",
|
||||
debt_purchase_amount=457700000000000000000,
|
||||
received_amount=10111753901939162887,
|
||||
protocol=Protocol.aave,
|
||||
transaction_hash=transaction1,
|
||||
block_number=block_number,
|
||||
)
|
||||
|
||||
liquidation2 = Liquidation(
|
||||
liquidated_user="0x6c6541ae8a7c6a6f968124a5ff2feac8f0c7875b",
|
||||
liquidator_user="0x7185e240d8e9e2d692cbc68d30eecf965e9a7feb",
|
||||
collateral_token_address="0x514910771af9ca656af840dff83e8264ecf986ca",
|
||||
debt_token_address="0x0000000000085d4780b73119b644ae5ecd22b376",
|
||||
debt_purchase_amount=497030000000000000000,
|
||||
received_amount=21996356316098208090,
|
||||
protocol=Protocol.aave,
|
||||
transaction_hash=transaction2,
|
||||
block_number=block_number,
|
||||
)
|
||||
|
||||
liquidation3 = Liquidation(
|
||||
liquidated_user="0xda874f844389df33c0fad140df4970fe1b366726",
|
||||
liquidator_user="0x7185e240d8e9e2d692cbc68d30eecf965e9a7feb",
|
||||
collateral_token_address="0x9f8f72aa9304c8b593d555f12ef6589cc3a579a2",
|
||||
debt_token_address="0x57ab1ec28d129707052df4df418d58a2d46d5f51",
|
||||
debt_purchase_amount=447810000000000000000,
|
||||
received_amount=121531358145247546,
|
||||
protocol=Protocol.aave,
|
||||
transaction_hash=transaction3,
|
||||
block_number=block_number,
|
||||
)
|
||||
|
||||
block = load_test_block(block_number)
|
||||
trace_classifier = TraceClassifier()
|
||||
classified_traces = trace_classifier.classify(block.traces)
|
||||
result = get_aave_liquidations(classified_traces)
|
||||
liquidations = [liquidation1, liquidation2, liquidation3]
|
||||
|
||||
_assert_equal_list_of_liquidations(result, liquidations)
|
||||
|
||||
|
||||
def _assert_equal_list_of_liquidations(
|
||||
actual_liquidations: List[Liquidation], expected_liquidations: List[Liquidation]
|
||||
):
|
||||
for i in range(len(actual_liquidations)):
|
||||
assert actual_liquidations[i] == expected_liquidations[i]
|
||||
|
Loading…
x
Reference in New Issue
Block a user