Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add 4byte, ens, refactor etherscan #50

Merged
merged 11 commits into from
Oct 5, 2021
24 changes: 12 additions & 12 deletions ethtx/decoders/abi/abc.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,14 @@
from typing import Optional, Any, List, Dict

from ethtx.models.decoded_model import DecodedCall, DecodedTransfer, Proxy
from ethtx.models.objects_model import Block, Transaction, Call, Event, TransactionMetadata, BlockMetadata
from ethtx.models.objects_model import (
Block,
Transaction,
Call,
Event,
TransactionMetadata,
BlockMetadata,
)
from ethtx.providers.semantic_providers.semantics_repository import SemanticsRepository


Expand Down Expand Up @@ -42,10 +49,7 @@ def __init__(

@abstractmethod
def decode_transaction(
self,
block: Block,
transaction: Transaction,
proxies: Dict[str, Proxy],
self, block: Block, transaction: Transaction, proxies: Dict[str, Proxy]
):
...

Expand All @@ -55,7 +59,7 @@ def decode_calls(
call: Call,
block: BlockMetadata,
transaction: TransactionMetadata,
proxies: Dict[str, Proxy]
proxies: Dict[str, Proxy],
) -> ABISubmoduleAbc.decode:
...

Expand All @@ -71,16 +75,12 @@ def decode_events(

@abstractmethod
def decode_transfers(
self,
call: DecodedCall,
events: [Event],
proxies: Dict[str, Proxy]
self, call: DecodedCall, events: [Event], proxies: Dict[str, Proxy]
) -> ABISubmoduleAbc.decode:
...

@abstractmethod
def decode_balances(
self,
transfers: List[DecodedTransfer]
self, transfers: List[DecodedTransfer]
) -> ABISubmoduleAbc.decode:
...
4 changes: 2 additions & 2 deletions ethtx/decoders/abi/balances.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,8 @@ class ABIBalancesDecoder(ABISubmoduleAbc):
def decode(self, transfers: List[DecodedTransfer]) -> List:
"""Decode balances."""

balance_holders = dict()
balance_tokens = dict()
balance_holders = {}
balance_tokens = {}

for transfer in transfers:
if transfer.from_address.address != ZERO_ADDRESS:
Expand Down
62 changes: 41 additions & 21 deletions ethtx/decoders/abi/calls.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,20 +9,21 @@
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import logging
from typing import Optional, Dict

from ethtx.models.decoded_model import DecodedCall, Proxy
from ethtx.models.objects_model import Call, TransactionMetadata, BlockMetadata
from ethtx.utils.measurable import RecursionLimit

from ethtx.semantics.solidity.precompiles import precompiles
from ethtx.semantics.standards.erc20 import ERC20_FUNCTIONS
from ethtx.semantics.standards.erc721 import ERC721_FUNCTIONS
from ethtx.semantics.solidity.precompiles import precompiles

from ethtx.utils.measurable import RecursionLimit
from .abc import ABISubmoduleAbc
from .helpers.utils import decode_function_abi_with_external_source
from ..decoders.parameters import decode_function_parameters, decode_graffiti_parameters

log = logging.getLogger(__name__)

RECURSION_LIMIT = 2000


Expand All @@ -47,14 +48,7 @@ def decode(
call_id = ""

decoded_root_call = self.decode_call(
call,
block,
transaction,
call_id,
indent,
status,
proxies or {},
chain_id,
call, block, transaction, call_id, indent, status, proxies or {}, chain_id
)

with RecursionLimit(RECURSION_LIMIT):
Expand Down Expand Up @@ -97,9 +91,7 @@ def decode_call(
chain_id, call.from_address, proxies
)

to_name = self._repository.get_address_label(
chain_id, call.to_address, proxies
)
to_name = self._repository.get_address_label(chain_id, call.to_address, proxies)

if call.call_type == "selfdestruct":
function_name = call.call_type
Expand All @@ -114,19 +106,22 @@ def decode_call(
function_input, function_output = [], []

elif self._repository.check_is_contract(chain_id, call.to_address):

standard = self._repository.get_standard(chain_id, call.to_address)

function_abi = self._repository.get_function_abi(
chain_id, call.to_address, function_signature
)

function_signature = call.call_data[:10] if call.call_data else ''
function_signature = call.call_data[:10] if call.call_data else ""

if not function_abi and call.to_address in proxies:
# try to find signature in delegate-called contracts
for semantic in proxies[call.to_address].semantics:
function_abi = semantic.contract.functions[function_signature] if function_signature in semantic.contract.functions else None
function_abi = (
semantic.contract.functions[function_signature]
if function_signature in semantic.contract.functions
else None
)
if function_abi:
break

Expand All @@ -139,9 +134,31 @@ def decode_call(
function_abi = ERC721_FUNCTIONS.get(function_signature)

function_name = function_abi.name if function_abi else function_signature

function_input, function_output = decode_function_parameters(
call.call_data, call.return_value, function_abi, call.status
)

if function_name.startswith("0x") and len(function_signature) > 2:
functions_abi_provider = decode_function_abi_with_external_source(
signature=function_signature, repository=self._repository
)
for function_abi_provider in functions_abi_provider:
try:
function_abi = function_abi_provider
function_name = function_abi.name
function_input, function_output = decode_function_parameters(
call.call_data, call.return_value, function_abi, call.status
)
except Exception as e:
log.info(
"Skipping getting function from external source and trying to get next. Error: %s",
e,
)
continue
else:
break

if (
not call.status
and function_output
Expand All @@ -154,8 +171,11 @@ def decode_call(
function_semantics = precompiles[int(call.to_address, 16)]
function_name = function_semantics.name
function_input, function_output = decode_function_parameters(
call.call_data, call.return_value, function_semantics, call.status,
strip_signature=False
call.call_data,
call.return_value,
function_semantics,
call.status,
strip_signature=False,
)
else:
function_name = "fallback"
Expand Down
45 changes: 13 additions & 32 deletions ethtx/decoders/abi/decoder.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
DecodedCall,
DecodedEvent,
DecodedTransfer,
Proxy
Proxy,
)
from ethtx.models.objects_model import (
Block,
Expand Down Expand Up @@ -50,10 +50,7 @@ def decode_transaction(
log.info("ABI decoding for %s / %s.", transaction.metadata.tx_hash, chain_id)

try:
with ExecutionTimer(f"ABI decoding for " + transaction.metadata.tx_hash):
log.info(
"ABI decoding for %s / %s.", transaction.metadata.tx_hash, chain_id
)
with ExecutionTimer("ABI decoding for " + transaction.metadata.tx_hash):
full_decoded_transaction = self._decode_transaction(
block.metadata, transaction, chain_id, proxies
)
Expand Down Expand Up @@ -82,7 +79,7 @@ def decode_calls(
block=block,
transaction=transaction,
proxies=proxies,
chain_id=chain_id or self._default_chain
chain_id=chain_id or self._default_chain,
)

def decode_call(
Expand All @@ -94,12 +91,7 @@ def decode_call(
) -> Optional[DecodedCall]:
return ABICallsDecoder(
repository=self._repository, chain_id=self._default_chain
).decode(
call=root_call,
block=block,
transaction=transaction,
proxies=proxies,
)
).decode(call=root_call, block=block, transaction=transaction, proxies=proxies)

def decode_events(
self,
Expand All @@ -116,7 +108,7 @@ def decode_events(
block=block,
transaction=transaction,
proxies=proxies or {},
chain_id=chain_id or self._default_chain
chain_id=chain_id or self._default_chain,
)

def decode_event(
Expand All @@ -134,7 +126,7 @@ def decode_event(
block=block,
transaction=transaction,
proxies=proxies or {},
chain_id=chain_id or self._default_chain
chain_id=chain_id or self._default_chain,
)

def decode_transfers(
Expand All @@ -146,11 +138,7 @@ def decode_transfers(
):
return ABITransfersDecoder(
repository=self._repository, chain_id=chain_id or self._default_chain
).decode(
call=call,
events=events,
proxies=proxies or {},
)
).decode(call=call, events=events, proxies=proxies or {})

def decode_balances(self, transfers: List[DecodedTransfer]):
return ABIBalancesDecoder(
Expand Down Expand Up @@ -178,11 +166,7 @@ def _decode_transaction(

try:
full_decoded_transaction.events = self.decode_events(
transaction.events,
block,
transaction.metadata,
proxies,
chain_id
transaction.events, block, transaction.metadata, proxies, chain_id
)
except Exception:
log.exception(
Expand All @@ -194,11 +178,7 @@ def _decode_transaction(

try:
full_decoded_transaction.calls = self.decode_calls(
transaction.root_call,
block,
transaction.metadata,
proxies,
chain_id
transaction.root_call, block, transaction.metadata, proxies, chain_id
)
except Exception:
log.exception(
Expand All @@ -213,7 +193,7 @@ def _decode_transaction(
full_decoded_transaction.calls,
full_decoded_transaction.events,
proxies,
chain_id
chain_id,
)
except Exception:
log.exception(
Expand All @@ -237,8 +217,9 @@ def _decode_transaction(

used_semantics = self._repository.end_record()
log.info(
f"Semantics used in decoding {transaction.metadata.tx_hash}: "
+ ", ".join(used_semantics)
"Semantics used in decoding %s: %s ",
transaction.metadata.tx_hash,
", ".join(used_semantics),
)

full_decoded_transaction.status = True
Expand Down
Loading