Merge pull request #143 from flashbots/0x-v2
Add support for 0x orderbook
This commit is contained in:
commit
4304776af6
@ -1,10 +1,59 @@
|
||||
from typing import Optional, List, Tuple
|
||||
from mev_inspect.schemas.transfers import Transfer
|
||||
from mev_inspect.schemas.swaps import Swap
|
||||
from mev_inspect.schemas.traces import (
|
||||
DecodedCallTrace,
|
||||
Protocol,
|
||||
)
|
||||
from mev_inspect.schemas.classifiers import (
|
||||
ClassifierSpec,
|
||||
SwapClassifier,
|
||||
)
|
||||
|
||||
ANY_TAKER_ADDRESS = "0x0000000000000000000000000000000000000000"
|
||||
|
||||
RFQ_SIGNATURES = [
|
||||
"fillRfqOrder((address,address,uint128,uint128,address,address,address,bytes32,uint64,uint256),(uint8,uint8,bytes32,bytes32),uint128)",
|
||||
"_fillRfqOrder((address,address,uint128,uint128,address,address,address,bytes32,uint64,uint256),(uint8,uint8,bytes32,bytes32),uint128,address,bool,address)",
|
||||
]
|
||||
LIMIT_SIGNATURES = [
|
||||
"fillOrKillLimitOrder((address,address,uint128,uint128,uint128,address,address,address,address,bytes32,uint64,uint256),(uint8,uint8,bytes32,bytes32),uint128)",
|
||||
"fillLimitOrder((address,address,uint128,uint128,uint128,address,address,address,address,bytes32,uint64,uint256),(uint8,uint8,bytes32,bytes32),uint128)",
|
||||
"_fillLimitOrder((address,address,uint128,uint128,uint128,address,address,address,address,bytes32,uint64,uint256),(uint8,uint8,bytes32,bytes32),uint128,address,address)",
|
||||
]
|
||||
|
||||
|
||||
class ZeroExSwapClassifier(SwapClassifier):
|
||||
@staticmethod
|
||||
def parse_swap(
|
||||
trace: DecodedCallTrace,
|
||||
prior_transfers: List[Transfer],
|
||||
child_transfers: List[Transfer],
|
||||
) -> Optional[Swap]:
|
||||
|
||||
token_in_address, token_in_amount = _get_0x_token_in_data(
|
||||
trace, child_transfers
|
||||
)
|
||||
|
||||
token_out_address, token_out_amount = _get_0x_token_out_data(trace)
|
||||
|
||||
return Swap(
|
||||
abi_name=trace.abi_name,
|
||||
transaction_hash=trace.transaction_hash,
|
||||
block_number=trace.block_number,
|
||||
trace_address=trace.trace_address,
|
||||
contract_address=trace.to_address,
|
||||
protocol=Protocol.zero_ex,
|
||||
from_address=trace.from_address,
|
||||
to_address=trace.to_address,
|
||||
token_in_address=token_in_address,
|
||||
token_in_amount=token_in_amount,
|
||||
token_out_address=token_out_address,
|
||||
token_out_amount=token_out_amount,
|
||||
error=trace.error,
|
||||
)
|
||||
|
||||
|
||||
ZEROX_CONTRACT_SPECS = [
|
||||
ClassifierSpec(
|
||||
abi_name="exchangeProxy",
|
||||
@ -121,6 +170,14 @@ ZEROX_GENERIC_SPECS = [
|
||||
ClassifierSpec(
|
||||
abi_name="INativeOrdersFeature",
|
||||
protocol=Protocol.zero_ex,
|
||||
valid_contract_addresses=["0xdef1c0ded9bec7f1a1670819833240f027b25eff"],
|
||||
classifiers={
|
||||
"fillOrKillLimitOrder((address,address,uint128,uint128,uint128,address,address,address,address,bytes32,uint64,uint256),(uint8,uint8,bytes32,bytes32),uint128)": ZeroExSwapClassifier,
|
||||
"fillRfqOrder((address,address,uint128,uint128,address,address,address,bytes32,uint64,uint256),(uint8,uint8,bytes32,bytes32),uint128)": ZeroExSwapClassifier,
|
||||
"fillLimitOrder((address,address,uint128,uint128,uint128,address,address,address,address,bytes32,uint64,uint256),(uint8,uint8,bytes32,bytes32),uint128)": ZeroExSwapClassifier,
|
||||
"_fillRfqOrder((address,address,uint128,uint128,address,address,address,bytes32,uint64,uint256),(uint8,uint8,bytes32,bytes32),uint128,address,bool,address)": ZeroExSwapClassifier,
|
||||
"_fillLimitOrder((address,address,uint128,uint128,uint128,address,address,address,address,bytes32,uint64,uint256),(uint8,uint8,bytes32,bytes32),uint128,address,address)": ZeroExSwapClassifier,
|
||||
},
|
||||
),
|
||||
ClassifierSpec(
|
||||
abi_name="IOtcOrdersFeature",
|
||||
@ -165,3 +222,57 @@ ZEROX_GENERIC_SPECS = [
|
||||
]
|
||||
|
||||
ZEROX_CLASSIFIER_SPECS = ZEROX_CONTRACT_SPECS + ZEROX_GENERIC_SPECS
|
||||
|
||||
|
||||
def _get_taker_token_in_amount(
|
||||
taker_address: str, token_in_address: str, child_transfers: List[Transfer]
|
||||
) -> int:
|
||||
|
||||
if len(child_transfers) != 2:
|
||||
raise ValueError(
|
||||
f"A settled order should consist of 2 child transfers, not {len(child_transfers)}."
|
||||
)
|
||||
|
||||
if taker_address == ANY_TAKER_ADDRESS:
|
||||
for transfer in child_transfers:
|
||||
if transfer.token_address == token_in_address:
|
||||
return transfer.amount
|
||||
else:
|
||||
for transfer in child_transfers:
|
||||
if transfer.to_address == taker_address:
|
||||
return transfer.amount
|
||||
return 0
|
||||
|
||||
|
||||
def _get_0x_token_in_data(
|
||||
trace: DecodedCallTrace, child_transfers: List[Transfer]
|
||||
) -> Tuple[str, int]:
|
||||
|
||||
order: List = trace.inputs["order"]
|
||||
token_in_address = order[0]
|
||||
|
||||
if trace.function_signature in RFQ_SIGNATURES:
|
||||
taker_address = order[5]
|
||||
|
||||
elif trace.function_signature in LIMIT_SIGNATURES:
|
||||
taker_address = order[6]
|
||||
|
||||
else:
|
||||
raise RuntimeError(
|
||||
f"0x orderbook function {trace.function_signature} is not supported"
|
||||
)
|
||||
|
||||
token_in_amount = _get_taker_token_in_amount(
|
||||
taker_address, token_in_address, child_transfers
|
||||
)
|
||||
|
||||
return token_in_address, token_in_amount
|
||||
|
||||
|
||||
def _get_0x_token_out_data(trace: DecodedCallTrace) -> Tuple[str, int]:
|
||||
|
||||
order: List = trace.inputs["order"]
|
||||
token_out_address = order[1]
|
||||
token_out_amount = trace.inputs["takerTokenFillAmount"]
|
||||
|
||||
return token_out_address, token_out_amount
|
||||
|
1
tests/blocks/13666184.json
Normal file
1
tests/blocks/13666184.json
Normal file
File diff suppressed because one or more lines are too long
1
tests/blocks/13666312.json
Normal file
1
tests/blocks/13666312.json
Normal file
File diff suppressed because one or more lines are too long
1
tests/blocks/13666326.json
Normal file
1
tests/blocks/13666326.json
Normal file
File diff suppressed because one or more lines are too long
1
tests/blocks/13666363.json
Normal file
1
tests/blocks/13666363.json
Normal file
File diff suppressed because one or more lines are too long
129
tests/test_0x.py
Normal file
129
tests/test_0x.py
Normal file
@ -0,0 +1,129 @@
|
||||
from mev_inspect.schemas.swaps import Swap
|
||||
from mev_inspect.swaps import get_swaps
|
||||
from mev_inspect.schemas.traces import Protocol
|
||||
from mev_inspect.classifiers.trace import TraceClassifier
|
||||
from tests.utils import load_test_block
|
||||
|
||||
|
||||
def test_fillLimitOrder_swap():
|
||||
|
||||
transaction_hash = (
|
||||
"0xa043976d736ec8dc930c0556dffd0a86a4bfc80bf98fb7995c791fb4dc488b5d"
|
||||
)
|
||||
block_number = 13666312
|
||||
|
||||
swap = Swap(
|
||||
abi_name="INativeOrdersFeature",
|
||||
transaction_hash=transaction_hash,
|
||||
block_number=block_number,
|
||||
trace_address=[0, 2, 0, 1],
|
||||
contract_address="0xdef1c0ded9bec7f1a1670819833240f027b25eff",
|
||||
from_address="0x00000000000e1d0dabf7b7c7b68866fc940d0db8",
|
||||
to_address="0xdef1c0ded9bec7f1a1670819833240f027b25eff",
|
||||
token_in_address="0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2",
|
||||
token_in_amount=35000000000000000000,
|
||||
token_out_address="0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48",
|
||||
token_out_amount=143949683150,
|
||||
protocol=Protocol.zero_ex,
|
||||
error=None,
|
||||
)
|
||||
|
||||
block = load_test_block(block_number)
|
||||
trace_classifier = TraceClassifier()
|
||||
classified_traces = trace_classifier.classify(block.traces)
|
||||
result = get_swaps(classified_traces)
|
||||
|
||||
assert result.count(swap) == 1
|
||||
|
||||
|
||||
def test__fillLimitOrder_swap():
|
||||
|
||||
transaction_hash = (
|
||||
"0x9255addffa2dbeb9560c5e20e78a78c949488d2054c70b2155c39f9e28394cbf"
|
||||
)
|
||||
block_number = 13666184
|
||||
|
||||
swap = Swap(
|
||||
abi_name="INativeOrdersFeature",
|
||||
transaction_hash=transaction_hash,
|
||||
block_number=block_number,
|
||||
trace_address=[0, 1],
|
||||
contract_address="0xdef1c0ded9bec7f1a1670819833240f027b25eff",
|
||||
from_address="0xdef1c0ded9bec7f1a1670819833240f027b25eff",
|
||||
to_address="0xdef1c0ded9bec7f1a1670819833240f027b25eff",
|
||||
token_in_address="0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48",
|
||||
token_in_amount=30000000,
|
||||
token_out_address="0x9ff79c75ae2bcbe0ec63c0375a3ec90ff75bbe0f",
|
||||
token_out_amount=100000001,
|
||||
protocol=Protocol.zero_ex,
|
||||
error=None,
|
||||
)
|
||||
|
||||
block = load_test_block(block_number)
|
||||
trace_classifier = TraceClassifier()
|
||||
classified_traces = trace_classifier.classify(block.traces)
|
||||
result = get_swaps(classified_traces)
|
||||
|
||||
assert result.count(swap) == 1
|
||||
|
||||
|
||||
def test_RfqLimitOrder_swap():
|
||||
|
||||
transaction_hash = (
|
||||
"0x1c948eb7c59ddbe6b916cf68f5df86eb44a7c9e728221fcd8ab750f137fd2a0f"
|
||||
)
|
||||
block_number = 13666326
|
||||
|
||||
swap = Swap(
|
||||
abi_name="INativeOrdersFeature",
|
||||
transaction_hash=transaction_hash,
|
||||
block_number=block_number,
|
||||
trace_address=[0, 1, 13, 0, 1],
|
||||
contract_address="0xdef1c0ded9bec7f1a1670819833240f027b25eff",
|
||||
from_address="0xdef171fe48cf0115b1d80b88dc8eab59176fee57",
|
||||
to_address="0xdef1c0ded9bec7f1a1670819833240f027b25eff",
|
||||
token_in_address="0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48",
|
||||
token_in_amount=288948250430,
|
||||
token_out_address="0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2",
|
||||
token_out_amount=70500000000000000000,
|
||||
protocol=Protocol.zero_ex,
|
||||
error=None,
|
||||
)
|
||||
|
||||
block = load_test_block(block_number)
|
||||
trace_classifier = TraceClassifier()
|
||||
classified_traces = trace_classifier.classify(block.traces)
|
||||
result = get_swaps(classified_traces)
|
||||
|
||||
assert result.count(swap) == 1
|
||||
|
||||
|
||||
def test__RfqLimitOrder_swap():
|
||||
|
||||
transaction_hash = (
|
||||
"0x4f66832e654f8a4d773d9769571155df3722401343247376d6bb56626db29b90"
|
||||
)
|
||||
block_number = 13666363
|
||||
|
||||
swap = Swap(
|
||||
abi_name="INativeOrdersFeature",
|
||||
transaction_hash=transaction_hash,
|
||||
block_number=block_number,
|
||||
trace_address=[1, 0, 1, 0, 1],
|
||||
contract_address="0xdef1c0ded9bec7f1a1670819833240f027b25eff",
|
||||
from_address="0xdef1c0ded9bec7f1a1670819833240f027b25eff",
|
||||
to_address="0xdef1c0ded9bec7f1a1670819833240f027b25eff",
|
||||
token_in_address="0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2",
|
||||
token_in_amount=979486121594935552,
|
||||
token_out_address="0x95ad61b0a150d79219dcf64e1e6cc01f0b64c4ce",
|
||||
token_out_amount=92404351093861841165644172,
|
||||
protocol=Protocol.zero_ex,
|
||||
error=None,
|
||||
)
|
||||
|
||||
block = load_test_block(block_number)
|
||||
trace_classifier = TraceClassifier()
|
||||
classified_traces = trace_classifier.classify(block.traces)
|
||||
result = get_swaps(classified_traces)
|
||||
|
||||
assert result.count(swap) == 1
|
Loading…
x
Reference in New Issue
Block a user