Swamps, transfers, tests imp
This commit is contained in:
parent
2db5794cde
commit
e5cb9335ca
@ -1,8 +1,7 @@
|
|||||||
from itertools import groupby
|
from itertools import groupby
|
||||||
from typing import List, Optional
|
from typing import List, Optional
|
||||||
|
|
||||||
from mev_inspect.schemas.arbitrages import Arbitrage
|
from mev_inspect.schemas.classified_traces import Swap, Arbitrage
|
||||||
from mev_inspect.schemas.swaps import Swap
|
|
||||||
|
|
||||||
|
|
||||||
def get_arbitrages(swaps: List[Swap]) -> List[Arbitrage]:
|
def get_arbitrages(swaps: List[Swap]) -> List[Arbitrage]:
|
||||||
|
@ -2,7 +2,7 @@ from typing import List
|
|||||||
|
|
||||||
from pydantic import BaseModel
|
from pydantic import BaseModel
|
||||||
|
|
||||||
from .swaps import Swap
|
from .classified_traces import Swap
|
||||||
|
|
||||||
|
|
||||||
class Arbitrage(BaseModel):
|
class Arbitrage(BaseModel):
|
||||||
|
@ -43,11 +43,8 @@ class TraceType(Enum):
|
|||||||
|
|
||||||
|
|
||||||
class Trace(CamelModel):
|
class Trace(CamelModel):
|
||||||
action: dict
|
|
||||||
block_hash: str
|
|
||||||
block_number: int
|
block_number: int
|
||||||
result: Optional[dict]
|
result: Optional[dict]
|
||||||
subtraces: int
|
|
||||||
trace_address: List[int]
|
trace_address: List[int]
|
||||||
transaction_hash: Optional[str]
|
transaction_hash: Optional[str]
|
||||||
transaction_position: Optional[int]
|
transaction_position: Optional[int]
|
||||||
|
@ -1,9 +1,14 @@
|
|||||||
from enum import Enum
|
from enum import Enum
|
||||||
|
|
||||||
from typing import Any, Dict, List, Optional
|
from typing import Any, Dict, List, Optional
|
||||||
|
|
||||||
from pydantic import BaseModel
|
from pydantic import BaseModel
|
||||||
|
|
||||||
from .blocks import TraceType
|
from .blocks import Trace
|
||||||
|
|
||||||
|
from .utils import CamelModel
|
||||||
|
|
||||||
|
# -------- Enums ------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
class Classification(Enum):
|
class Classification(Enum):
|
||||||
@ -23,23 +28,29 @@ class Protocol(Enum):
|
|||||||
curve = "curve"
|
curve = "curve"
|
||||||
|
|
||||||
|
|
||||||
class ClassifiedTrace(BaseModel):
|
# -------- Trace Models ------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
class ClassifiedTrace(Trace):
|
||||||
|
|
||||||
transaction_hash: str
|
transaction_hash: str
|
||||||
block_number: int
|
block_number: int
|
||||||
trace_type: TraceType
|
|
||||||
trace_address: List[int]
|
trace_address: List[int]
|
||||||
classification: Classification
|
classification: Classification
|
||||||
protocol: Optional[Protocol]
|
error: Optional[str]
|
||||||
abi_name: Optional[str]
|
block_hash: Optional[str]
|
||||||
function_name: Optional[str]
|
subtraces: Optional[int]
|
||||||
function_signature: Optional[str]
|
action: Optional[dict]
|
||||||
inputs: Optional[Dict[str, Any]]
|
|
||||||
to_address: Optional[str]
|
to_address: Optional[str]
|
||||||
from_address: Optional[str]
|
from_address: Optional[str]
|
||||||
gas: Optional[int]
|
gas: Optional[int]
|
||||||
value: Optional[int]
|
value: Optional[int]
|
||||||
gas_used: Optional[int]
|
gas_used: Optional[int]
|
||||||
error: Optional[str]
|
protocol: Optional[Protocol]
|
||||||
|
function_name: Optional[str]
|
||||||
|
function_signature: Optional[str]
|
||||||
|
inputs: Optional[Dict[str, Any]]
|
||||||
|
abi_name: Optional[str]
|
||||||
|
|
||||||
class Config:
|
class Config:
|
||||||
json_encoders = {
|
json_encoders = {
|
||||||
@ -49,6 +60,135 @@ class ClassifiedTrace(BaseModel):
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class Call(ClassifiedTrace):
|
||||||
|
|
||||||
|
to_address: str
|
||||||
|
from_address: str
|
||||||
|
inputs: Dict[str, Any]
|
||||||
|
|
||||||
|
|
||||||
|
class ClassifiedCall(ClassifiedTrace):
|
||||||
|
gas: Optional[int]
|
||||||
|
gas_used: Optional[int]
|
||||||
|
function_name: Optional[str]
|
||||||
|
function_signature: Optional[str]
|
||||||
|
abi_name: str
|
||||||
|
|
||||||
|
class Config:
|
||||||
|
json_encoders = {
|
||||||
|
# a little lazy but fine for now
|
||||||
|
# this is used for bytes value inputs
|
||||||
|
bytes: lambda b: b.hex(),
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
# -------- Swaps ------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
class Swap(BaseModel):
|
||||||
|
abi_name: str
|
||||||
|
transaction_hash: str
|
||||||
|
block_number: int
|
||||||
|
trace_address: List[int]
|
||||||
|
protocol: Optional[Protocol]
|
||||||
|
pool_address: str
|
||||||
|
from_address: str
|
||||||
|
to_address: str
|
||||||
|
token_in_address: str
|
||||||
|
token_in_amount: int
|
||||||
|
token_out_address: str
|
||||||
|
token_out_amount: int
|
||||||
|
error: Optional[str]
|
||||||
|
|
||||||
|
|
||||||
|
class Arbitrage(BaseModel):
|
||||||
|
swaps: List[Swap]
|
||||||
|
block_number: int
|
||||||
|
transaction_hash: str
|
||||||
|
account_address: str
|
||||||
|
profit_token_address: str
|
||||||
|
start_amount: int
|
||||||
|
end_amount: int
|
||||||
|
profit_amount: int
|
||||||
|
|
||||||
|
|
||||||
|
# -------- Transfers------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
class Transfer(BaseModel):
|
||||||
|
transaction_hash: str
|
||||||
|
trace_address: List[int]
|
||||||
|
from_address: str
|
||||||
|
to_address: str
|
||||||
|
amount: int
|
||||||
|
token_address: str
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def from_trace(cls, trace: ClassifiedTrace) -> "Transfer":
|
||||||
|
if trace.classification != Classification.transfer or trace.inputs is None:
|
||||||
|
raise ValueError("Invalid transfer")
|
||||||
|
|
||||||
|
if trace.protocol == Protocol.weth:
|
||||||
|
return cls(
|
||||||
|
transaction_hash=trace.transaction_hash,
|
||||||
|
trace_address=trace.trace_address,
|
||||||
|
amount=trace.inputs["wad"],
|
||||||
|
to_address=trace.inputs["dst"],
|
||||||
|
from_address=trace.from_address,
|
||||||
|
token_address=trace.to_address,
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
return cls(
|
||||||
|
transaction_hash=trace.transaction_hash,
|
||||||
|
trace_address=trace.trace_address,
|
||||||
|
amount=trace.inputs["amount"],
|
||||||
|
to_address=trace.inputs["recipient"],
|
||||||
|
from_address=trace.inputs.get("sender", trace.from_address),
|
||||||
|
token_address=trace.to_address,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
# -------- Liquidations ------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
class LiquidationType(Enum):
|
||||||
|
compound_v2_ceth_liquidation = "compound_v2_ceth_liquidation"
|
||||||
|
compound_v2_ctoken_liquidation = "compound_v2_ctoken_liquidation" # TODO: add logic to handle ctoken liquidations
|
||||||
|
|
||||||
|
|
||||||
|
class LiquidationStatus(Enum):
|
||||||
|
seized = "seized" # succesfully completed
|
||||||
|
check = "check" # just a liquidation check. i.e searcher only checks if opportunity is still available and reverts accordingly
|
||||||
|
out_of_gas = "out_of_gas" # tx ran out of gas
|
||||||
|
|
||||||
|
|
||||||
|
class LiquidationCollateralSource(Enum):
|
||||||
|
aave_flashloan = "aave_flashloan"
|
||||||
|
dydx_flashloan = "dydx_flashloan"
|
||||||
|
uniswap_flashloan = "uniswap_flashloan"
|
||||||
|
searcher_eoa = "searcher_eoa" # searchers own funds
|
||||||
|
searcher_contract = "searcher_contract"
|
||||||
|
other = "other"
|
||||||
|
|
||||||
|
|
||||||
|
class Liquidation(CamelModel):
|
||||||
|
tx_hash: str
|
||||||
|
borrower: str # account that got liquidated
|
||||||
|
collateral_provided: str # collateral provided by searcher, 'ether' or token contract address
|
||||||
|
collateral_provided_amount: int # amount of collateral provided
|
||||||
|
asset_seized: str # asset that was given to searcher at a discount upon liquidation
|
||||||
|
asset_seized_amount: int # amount of asset that was given to searcher upon liquidation
|
||||||
|
profit_in_eth: int # profit estimated by strategy inspector
|
||||||
|
tokenflow_estimate_in_eth: int # profit estimated by tokenflow
|
||||||
|
tokenflow_diff: int # diff between tokenflow and strategy inspector
|
||||||
|
status: LiquidationStatus
|
||||||
|
type: LiquidationType
|
||||||
|
collateral_source: LiquidationCollateralSource
|
||||||
|
|
||||||
|
|
||||||
|
# -------- Config ------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
class ClassifierSpec(BaseModel):
|
class ClassifierSpec(BaseModel):
|
||||||
abi_name: str
|
abi_name: str
|
||||||
protocol: Optional[Protocol] = None
|
protocol: Optional[Protocol] = None
|
||||||
|
@ -1,21 +0,0 @@
|
|||||||
from typing import List, Optional
|
|
||||||
|
|
||||||
from pydantic import BaseModel
|
|
||||||
|
|
||||||
from mev_inspect.schemas.classified_traces import Protocol
|
|
||||||
|
|
||||||
|
|
||||||
class Swap(BaseModel):
|
|
||||||
abi_name: str
|
|
||||||
transaction_hash: str
|
|
||||||
block_number: int
|
|
||||||
trace_address: List[int]
|
|
||||||
protocol: Optional[Protocol]
|
|
||||||
pool_address: str
|
|
||||||
from_address: str
|
|
||||||
to_address: str
|
|
||||||
token_in_address: str
|
|
||||||
token_in_amount: int
|
|
||||||
token_out_address: str
|
|
||||||
token_out_amount: int
|
|
||||||
error: Optional[str]
|
|
@ -1,38 +0,0 @@
|
|||||||
from typing import List
|
|
||||||
|
|
||||||
from pydantic import BaseModel
|
|
||||||
|
|
||||||
from .classified_traces import Classification, ClassifiedTrace, Protocol
|
|
||||||
|
|
||||||
|
|
||||||
class Transfer(BaseModel):
|
|
||||||
transaction_hash: str
|
|
||||||
trace_address: List[int]
|
|
||||||
from_address: str
|
|
||||||
to_address: str
|
|
||||||
amount: int
|
|
||||||
token_address: str
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def from_trace(cls, trace: ClassifiedTrace) -> "Transfer":
|
|
||||||
if trace.classification != Classification.transfer or trace.inputs is None:
|
|
||||||
raise ValueError("Invalid transfer")
|
|
||||||
|
|
||||||
if trace.protocol == Protocol.weth:
|
|
||||||
return cls(
|
|
||||||
transaction_hash=trace.transaction_hash,
|
|
||||||
trace_address=trace.trace_address,
|
|
||||||
amount=trace.inputs["wad"],
|
|
||||||
to_address=trace.inputs["dst"],
|
|
||||||
from_address=trace.from_address,
|
|
||||||
token_address=trace.to_address,
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
return cls(
|
|
||||||
transaction_hash=trace.transaction_hash,
|
|
||||||
trace_address=trace.trace_address,
|
|
||||||
amount=trace.inputs["amount"],
|
|
||||||
to_address=trace.inputs["recipient"],
|
|
||||||
from_address=trace.inputs.get("sender", trace.from_address),
|
|
||||||
token_address=trace.to_address,
|
|
||||||
)
|
|
@ -4,9 +4,10 @@ from typing import List, Optional
|
|||||||
from mev_inspect.schemas.classified_traces import (
|
from mev_inspect.schemas.classified_traces import (
|
||||||
ClassifiedTrace,
|
ClassifiedTrace,
|
||||||
Classification,
|
Classification,
|
||||||
|
Swap,
|
||||||
|
Transfer,
|
||||||
)
|
)
|
||||||
from mev_inspect.schemas.swaps import Swap
|
|
||||||
from mev_inspect.schemas.transfers import Transfer
|
|
||||||
from mev_inspect.transfers import (
|
from mev_inspect.transfers import (
|
||||||
get_child_transfers,
|
get_child_transfers,
|
||||||
filter_transfers,
|
filter_transfers,
|
||||||
|
@ -1,7 +1,10 @@
|
|||||||
from typing import Dict, List, Optional
|
from typing import Dict, List, Optional
|
||||||
|
|
||||||
from mev_inspect.schemas.classified_traces import Classification, ClassifiedTrace
|
from mev_inspect.schemas.classified_traces import (
|
||||||
from mev_inspect.schemas.transfers import Transfer
|
Classification,
|
||||||
|
ClassifiedTrace,
|
||||||
|
Transfer,
|
||||||
|
)
|
||||||
from mev_inspect.traces import is_child_trace_address, get_child_traces
|
from mev_inspect.traces import is_child_trace_address, get_child_traces
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,7 +1,12 @@
|
|||||||
from typing import List
|
from typing import List
|
||||||
|
|
||||||
from mev_inspect.schemas.blocks import TraceType
|
from mev_inspect.schemas.blocks import TraceType
|
||||||
from mev_inspect.schemas.classified_traces import Classification, ClassifiedTrace
|
from mev_inspect.schemas.classified_traces import (
|
||||||
|
Classification,
|
||||||
|
ClassifiedTrace,
|
||||||
|
Call,
|
||||||
|
ClassifiedCall,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def make_transfer_trace(
|
def make_transfer_trace(
|
||||||
@ -13,10 +18,10 @@ def make_transfer_trace(
|
|||||||
token_address: str,
|
token_address: str,
|
||||||
amount: int,
|
amount: int,
|
||||||
):
|
):
|
||||||
return ClassifiedTrace(
|
return Call(
|
||||||
transaction_hash=transaction_hash,
|
transaction_hash=transaction_hash,
|
||||||
block_number=block_number,
|
block_number=block_number,
|
||||||
trace_type=TraceType.call,
|
type=TraceType.call,
|
||||||
trace_address=trace_address,
|
trace_address=trace_address,
|
||||||
classification=Classification.transfer,
|
classification=Classification.transfer,
|
||||||
from_address=from_address,
|
from_address=from_address,
|
||||||
@ -38,10 +43,10 @@ def make_swap_trace(
|
|||||||
recipient_address: str,
|
recipient_address: str,
|
||||||
recipient_input_key: str,
|
recipient_input_key: str,
|
||||||
):
|
):
|
||||||
return ClassifiedTrace(
|
return ClassifiedCall(
|
||||||
transaction_hash=transaction_hash,
|
transaction_hash=transaction_hash,
|
||||||
block_number=block_number,
|
block_number=block_number,
|
||||||
trace_type=TraceType.call,
|
type=TraceType.call,
|
||||||
trace_address=trace_address,
|
trace_address=trace_address,
|
||||||
classification=Classification.swap,
|
classification=Classification.swap,
|
||||||
from_address=from_address,
|
from_address=from_address,
|
||||||
@ -59,7 +64,7 @@ def make_unknown_trace(
|
|||||||
return ClassifiedTrace(
|
return ClassifiedTrace(
|
||||||
transaction_hash=transaction_hash,
|
transaction_hash=transaction_hash,
|
||||||
block_number=block_number,
|
block_number=block_number,
|
||||||
trace_type=TraceType.call,
|
type=TraceType.call,
|
||||||
trace_address=trace_address,
|
trace_address=trace_address,
|
||||||
classification=Classification.unknown,
|
classification=Classification.unknown,
|
||||||
)
|
)
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
from mev_inspect.arbitrages import get_arbitrages
|
from mev_inspect.arbitrages import get_arbitrages
|
||||||
from mev_inspect.schemas.swaps import Swap
|
from mev_inspect.schemas.classified_traces import Swap
|
||||||
from mev_inspect.swaps import (
|
from mev_inspect.swaps import (
|
||||||
UNISWAP_V2_PAIR_ABI_NAME,
|
UNISWAP_V2_PAIR_ABI_NAME,
|
||||||
UNISWAP_V3_POOL_ABI_NAME,
|
UNISWAP_V3_POOL_ABI_NAME,
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
from mev_inspect.schemas.transfers import Transfer
|
from mev_inspect.schemas.classified_traces import Transfer
|
||||||
from mev_inspect.transfers import remove_child_transfers_of_transfers
|
from mev_inspect.transfers import remove_child_transfers_of_transfers
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user