Merge pull request #74 from flashbots/aave-v0

Add AAVE liquidations to inspect_block
This commit is contained in:
Robert Miller 2021-09-30 13:58:37 -04:00 committed by GitHub
commit 4834d068f6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 241 additions and 20 deletions

View 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

View File

@ -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
)

View 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

View File

@ -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]]:

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -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]