Skip to content
This repository has been archived by the owner on Nov 27, 2024. It is now read-only.

Adjust sandwiches calculation #307

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 38 additions & 13 deletions mev_inspect/sandwiches.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,32 +42,57 @@ def _get_sandwich_starting_with_swap(
]:
return None

for other_swap in rest_swaps:
if other_swap.transaction_hash == front_swap.transaction_hash:
for back_swap in rest_swaps:
if back_swap.transaction_hash == front_swap.transaction_hash:
continue

if other_swap.contract_address == front_swap.contract_address:
if back_swap.contract_address == front_swap.contract_address:
if (
other_swap.token_in_address == front_swap.token_in_address
and other_swap.token_out_address == front_swap.token_out_address
and other_swap.from_address != sandwicher_address
back_swap.token_in_address == front_swap.token_in_address
and back_swap.token_out_address == front_swap.token_out_address
and back_swap.from_address != sandwicher_address
):
sandwiched_swaps.append(other_swap)
sandwiched_swaps.append(back_swap)
elif (
other_swap.token_out_address == front_swap.token_in_address
and other_swap.token_in_address == front_swap.token_out_address
and other_swap.from_address == sandwicher_address
back_swap.token_out_address == front_swap.token_in_address
and back_swap.token_in_address == front_swap.token_out_address
and back_swap.from_address == sandwicher_address

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⭐ for the rename.

):
if len(sandwiched_swaps) > 0:
profit_amount: float

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this formula needs some documentation in the code. Explain a little what is happening in here, and if you can put a math formula in clearer syntax than python code that would be nice.

@gheise how do we know if the formula is correct?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thanks for pointing that out, the reasons for this are mathematically expressible. I will add further detail on the PR about why i chose this formula and what it means, but i think we should leave this out of the code

if back_swap.token_in_amount == 0 and back_swap.error is None:
raise ValueError("Backrun cannot swap 0 tokens")

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This error doesn't have a test case.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we don't expect this to ever happen on chain; i added this here to be explicit about the assumption that the back swap must be ruled out in the case this value is 0 as to avoid a DivisionByZero error, so test coverage here would not be meaningful

if back_swap.token_in_amount == front_swap.token_out_amount:
profit_amount = (
back_swap.token_out_amount - front_swap.token_in_amount
)

if back_swap.token_in_amount > front_swap.token_out_amount:
exchange_rate = (
front_swap.token_out_amount / back_swap.token_in_amount
)
profit_amount = (
exchange_rate * back_swap.token_out_amount
- front_swap.token_in_amount
)

if back_swap.token_in_amount < front_swap.token_out_amount:
exchange_rate = (
back_swap.token_in_amount / front_swap.token_out_amount
)
profit_amount = (
back_swap.token_out_amount
- exchange_rate * front_swap.token_in_amount
)

return Sandwich(
block_number=front_swap.block_number,
sandwicher_address=sandwicher_address,
frontrun_swap=front_swap,
backrun_swap=other_swap,
backrun_swap=back_swap,
sandwiched_swaps=sandwiched_swaps,
profit_token_address=front_swap.token_in_address,
profit_amount=other_swap.token_out_amount
- front_swap.token_in_amount,
profit_amount=profit_amount,
)

return None
1 change: 1 addition & 0 deletions tests/blocks/13699765.json

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions tests/blocks/14659109.json

Large diffs are not rendered by default.

42 changes: 42 additions & 0 deletions tests/test_heavy_sandwiches.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
from typing import List

from mev_inspect.classifiers.trace import TraceClassifier
from mev_inspect.sandwiches import get_sandwiches
from mev_inspect.schemas.sandwiches import Sandwich
from mev_inspect.schemas.swaps import Swap
from mev_inspect.swaps import get_swaps
from tests.utils import load_test_block


def test_back_heavy_sandwich_profits(trace_classifier: TraceClassifier):
block_number = 13699765
expected_sandwicher = "0x51399b32cd0186bb32230e24167489f3b2f47870"
expected_token_address = "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"
expected_profit_amount = -435805264121298944

block = load_test_block(block_number)
classified_traces = trace_classifier.classify(block.traces)
swaps: List[Swap] = get_swaps(classified_traces)
result: List[Sandwich] = get_sandwiches(swaps)

for observed_sandwich in result:
if observed_sandwich.sandwicher_address == expected_sandwicher:
assert expected_token_address == observed_sandwich.profit_token_address
assert expected_profit_amount == observed_sandwich.profit_amount


def test_front_heavy_sandwich_profits(trace_classifier: TraceClassifier):
block_number = 14659109
expected_sandwicher = "0x01ff6318440f7d5553a82294d78262d5f5084eff"
expected_token_address = "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"
expected_profit_amount = -180511102573164864

block = load_test_block(block_number)
classified_traces = trace_classifier.classify(block.traces)
swaps: List[Swap] = get_swaps(classified_traces)
result: List[Sandwich] = get_sandwiches(swaps)

for observed_sandwich in result:
if observed_sandwich.sandwicher_address == expected_sandwicher:
assert expected_token_address == observed_sandwich.profit_token_address
assert expected_profit_amount == observed_sandwich.profit_amount