Skip to content

Commit

Permalink
feat: ether gains and losses
Browse files Browse the repository at this point in the history
  • Loading branch information
Otto-AA committed Aug 5, 2024
1 parent 93a43f4 commit c18c8d4
Show file tree
Hide file tree
Showing 10 changed files with 507 additions and 82 deletions.
Empty file.
65 changes: 65 additions & 0 deletions tests/analysis/snapshots/snap_test_currency_changes.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
# -*- coding: utf-8 -*-
# snapshottest: v1 - https://goo.gl/zC4yUc
from __future__ import unicode_literals

from snapshottest import GenericRepr, Snapshot


snapshots = Snapshot()

snapshots["test_currency_changes_extractor currency changes"] = [
(
GenericRepr("<CALL@000000000000000000000000000000000000aaaa:1#0>"),
{
"change": -10,
"owner": "0x000000000000000000000000000000000000aaaa",
"token_address": None,
"type": "ETHER",
},
),
(
GenericRepr("<CALL@000000000000000000000000000000000000aaaa:1#0>"),
{
"change": 10,
"owner": "0x000000000000000000000000000000000000bbbb",
"token_address": None,
"type": "ETHER",
},
),
(
GenericRepr("<CALLCODE@000000000000000000000000000000000000aaaa:1#0>"),
{
"change": -20,
"owner": "0x000000000000000000000000000000000000aaaa",
"token_address": None,
"type": "ETHER",
},
),
(
GenericRepr("<CALLCODE@000000000000000000000000000000000000aaaa:1#0>"),
{
"change": 20,
"owner": "0x000000000000000000000000000000000000cccc",
"token_address": None,
"type": "ETHER",
},
),
(
GenericRepr("<CALL@000000000000000000000000000000000000bbbb:1#0>"),
{
"change": -10,
"owner": "0x000000000000000000000000000000000000bbbb",
"token_address": None,
"type": "ETHER",
},
),
(
GenericRepr("<CALL@000000000000000000000000000000000000bbbb:1#0>"),
{
"change": 10,
"owner": "0x000000000000000000000000000000000000cccc",
"token_address": None,
"type": "ETHER",
},
),
]
29 changes: 29 additions & 0 deletions tests/analysis/test_currency_changes.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
from tests.test_utils.test_utils import (
_test_callcode,
)
from traces_analyzer.features.extractors.currency_changes import (
CurrencyChangesFeatureExtractor,
)
from tests.test_utils.test_utils import _test_call

from snapshottest.pytest import PyTestSnapshotTest


def test_currency_changes_extractor(snapshot: PyTestSnapshotTest):
instructions = [
# A -= 10 B += 10
_test_call("0xaaaa", 1, "0xa", "0xbbbb"),
# reverted
_test_call("0xaaaa", 1, "0xaa", "0xbbbb", reverted=True),
# A -= 20 C += 20
_test_callcode("0xaaaa", 1, "0x14", "0xcccc"),
# B -= 10 C += 10
_test_call("0xbbbb", 1, "0xa", "0xcccc"),
]

extractor = CurrencyChangesFeatureExtractor()
for instruction in instructions:
extractor.on_instruction(instruction)
changes = extractor.currency_changes

snapshot.assert_match(changes, "currency changes")
9 changes: 7 additions & 2 deletions tests/e2e/test_sample_traces_analysis.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,8 +81,13 @@ def test_sample_traces_analysis_e2e(
)

# Instruction usage has found 17 contracts
assert len(instruction_usage_analyzer.normal.get_used_opcodes_per_contract()) == 17
assert len(instruction_usage_analyzer.reverse.get_used_opcodes_per_contract()) == 17
assert (
len(instruction_usage_analyzer.normal.get_used_opcodes_per_contract()) == 17
)
assert (
len(instruction_usage_analyzer.reverse.get_used_opcodes_per_contract())
== 17
)

# TOD source
tod_source = tod_source_analyzer.get_tod_source()
Expand Down
51 changes: 51 additions & 0 deletions tests/evaluation/snapshots/snap_test_financial_gain_loss.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
# -*- coding: utf-8 -*-
# snapshottest: v1 - https://goo.gl/zC4yUc
from __future__ import unicode_literals

from snapshottest import Snapshot


snapshots = Snapshot()

snapshots["test_financial_gain_loss_evaluation evaluation_dict"] = {
"evaluation_type": "financial_gain_loss",
"report": {
"gains": {
"0x000000000000000000000000000000000000cccc": {
"ETHER": {
"change": 10,
"owner": "0x000000000000000000000000000000000000cccc",
"token_address": None,
"type": "ETHER",
}
}
},
"losses": {
"0x000000000000000000000000000000000000aaaa": {
"ETHER": {
"change": -8,
"owner": "0x000000000000000000000000000000000000aaaa",
"token_address": None,
"type": "ETHER",
}
},
"0x000000000000000000000000000000000000bbbb": {
"ETHER": {
"change": -2,
"owner": "0x000000000000000000000000000000000000bbbb",
"token_address": None,
"type": "ETHER",
}
},
},
},
}

snapshots[
"test_financial_gain_loss_evaluation evaluation_str"
] = """=== Evaluation: Financial gains and losses ===
Losses in normal compared to reverse scenario:
> 0x000000000000000000000000000000000000cccc lost 10 ETHER (in Wei)
"""
61 changes: 61 additions & 0 deletions tests/evaluation/test_financial_gain_loss.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import json
from typing import Sequence
from tests.test_utils.test_utils import (
_test_callcode,
)
from traces_analyzer.evaluation.financial_gain_loss_evaluation import (
FinancialGainLossEvaluation,
)
from traces_analyzer.features.extractors.currency_changes import (
CurrencyChangesFeatureExtractor,
)
from tests.test_utils.test_utils import _test_call
from traces_parser.parser.instructions.instruction import Instruction

from snapshottest.pytest import PyTestSnapshotTest


def get_changes(instructions: Sequence[Instruction]):
extractor = CurrencyChangesFeatureExtractor()
for instruction in instructions:
extractor.on_instruction(instruction)
return extractor.currency_changes


def test_financial_gain_loss_evaluation(snapshot: PyTestSnapshotTest):
changes_normal = get_changes(
[
# A -= 10 B += 10
_test_call("0xaaaa", 1, "0xa", "0xbbbb"),
# reverted
_test_call("0xaaaa", 1, "0xaa", "0xbbbb", reverted=True),
# A -= 20 C += 20
_test_callcode("0xaaaa", 1, "0x14", "0xcccc"),
# B -= 10 C += 10
_test_call("0xbbbb", 1, "0xa", "0xcccc"),
]
)
changes_reverse = get_changes(
[
# A -= 2 B += 2
_test_call("0xaaaa", 1, "0x2", "0xbbbb"),
# reverted
_test_call("0xaaaa", 1, "0xaa", "0xbbbb", reverted=True),
# A -= 20 C += 20
_test_callcode("0xaaaa", 1, "0x14", "0xcccc"),
]
)

evaluation = FinancialGainLossEvaluation(
changes_normal,
changes_reverse,
)

evaluation_dict = evaluation.dict_report()
snapshot.assert_match(evaluation_dict, "evaluation_dict")

evaluation_str = evaluation.cli_report()
snapshot.assert_match(evaluation_str, "evaluation_str")

# check if it's serializable
json.dumps(evaluation_dict)
32 changes: 30 additions & 2 deletions tests/test_utils/test_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
SLOAD,
CallInstruction,
CALL,
CALLCODE,
)
from traces_parser.parser.storage.address_key_storage import AddressKeyStorage
from traces_parser.parser.storage.balances import Balances
Expand Down Expand Up @@ -405,11 +406,38 @@ def _test_sstore(
)


def _test_call(current_address: str, pc: int, value: str, address: str):
def _test_call(current_address: str, pc: int, value: str, address: str, reverted=False):
return _test_instruction(
CALL,
pc=pc,
call_context=_test_call_context(code_address=_test_addr(current_address)),
call_context=_test_call_context(
code_address=_test_addr(current_address),
storage_address=_test_addr(current_address),
reverted=reverted,
),
flow=_test_flow(
accesses=StorageAccesses(
stack=_test_stack_accesses(
["0x1234", address, value, "0x0", "0x4", "0x0", "0x0"]
),
memory=[_test_mem_access("11111111")],
),
writes=StorageWrites(calldata=CalldataWrite(_test_group("11111111"))),
),
)


def _test_callcode(
current_address: str, pc: int, value: str, address: str, reverted=False
):
return _test_instruction(
CALLCODE,
pc=pc,
call_context=_test_call_context(
code_address=_test_addr(current_address),
storage_address=_test_addr(current_address),
reverted=reverted,
),
flow=_test_flow(
accesses=StorageAccesses(
stack=_test_stack_accesses(
Expand Down
Loading

0 comments on commit c18c8d4

Please sign in to comment.