Skip to content
Merged
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
33 changes: 33 additions & 0 deletions crypto/utils/abi/argument_decoder.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import binascii
from crypto.utils.abi_decoder import AbiDecoder

class ArgumentDecoder:
def __init__(self, hex_string: str):
try:
self.bytes = binascii.unhexlify(hex_string)
except binascii.Error:
self.bytes = b''

def decode_string(self) -> str:
value, _ = AbiDecoder.decode_string(self.bytes, 0)

return value

def decode_address(self) -> str:
value, _ = AbiDecoder.decode_address(self.bytes, 0)

return value

def decode_unsigned_int(self) -> int:
value, _ = AbiDecoder.decode_number(self.bytes, 0, False)

return value

def decode_signed_int(self) -> int:
value, _ = AbiDecoder.decode_number(self.bytes, 0, True)

return value

def decode_bool(self) -> bool:
value, _ = AbiDecoder.decode_bool(self.bytes, 0)
return value
21 changes: 13 additions & 8 deletions crypto/utils/abi_decoder.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,32 +64,36 @@ def decode_parameter(self, bytes_data, offset, param):
if match:
signed = match.group(1) == 'int'
bits = int(match.group(2))
return self.decode_number(bytes_data, offset, bits, signed)
return self.decode_number(bytes_data, offset, signed)
if type_ == 'tuple':
return self.decode_tuple(bytes_data, offset, param)
raise Exception('Unsupported type: ' + type_)

def decode_address(self, bytes_data, offset):
@staticmethod
def decode_address(bytes_data, offset):
data = bytes_data[offset:offset+32]
address_bytes = data[12:32]
address = '0x' + address_bytes.hex()
address = get_checksum_address(address)
return address, 32

def decode_bool(self, bytes_data, offset):
@staticmethod
def decode_bool(bytes_data, offset):
data = bytes_data[offset:offset+32]
value = int.from_bytes(data, byteorder='big') != 0
return value, 32

def decode_number(self, bytes_data, offset, bits, signed):
@staticmethod
def decode_number(bytes_data, offset, signed):
data = bytes_data[offset:offset+32]
value = int.from_bytes(data, byteorder='big', signed=signed)
return value, 32

def decode_string(self, bytes_data, offset):
data_offset = self.read_uint(bytes_data, offset)
@classmethod
def decode_string(cls, bytes_data, offset):
data_offset = cls.read_uint(bytes_data, offset)
string_offset = offset + data_offset
length = self.read_uint(bytes_data, string_offset)
length = cls.read_uint(bytes_data, string_offset)
string_data = bytes_data[string_offset+32:string_offset+32+length]
value = string_data.decode('utf-8')
return value, 32
Expand Down Expand Up @@ -140,6 +144,7 @@ def decode_tuple(self, bytes_data, offset, param):
values[name] = value
return values, 32

def read_uint(self, bytes_data, offset):
@staticmethod
def read_uint(bytes_data, offset):
data = bytes_data[offset:offset+32]
return int.from_bytes(data, byteorder='big')
42 changes: 42 additions & 0 deletions tests/utils/abi/test_argument_decoder.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
from crypto.utils.abi.argument_decoder import ArgumentDecoder


def test_it_should_decode_address():
payload = '000000000000000000000000512F366D524157BcF734546eB29a6d687B762255'
expected = '0x512F366D524157BcF734546eB29a6d687B762255'

decoder = ArgumentDecoder(payload)

assert decoder.decode_address() == expected

def test_it_should_decode_unsigned_int():
payload = '000000000000000000000000000000000000000000000000016345785d8a0000'
expected = 100000000000000000

decoder = ArgumentDecoder(payload)

assert decoder.decode_unsigned_int() == expected

def test_it_should_decode_signed_int():
payload = '000000000000000000000000000000000000000000000000016345785d8a0000'
expected = 100000000000000000

decoder = ArgumentDecoder(payload)

assert decoder.decode_signed_int() == expected

def test_it_should_decode_bool_as_true():
payload = '0000000000000000000000000000000000000000000000000000000000000001'
expected = True

decoder = ArgumentDecoder(payload)

assert decoder.decode_bool() == expected

def test_it_should_decode_bool_as_false():
payload = '0000000000000000000000000000000000000000000000000000000000000000'
expected = False

decoder = ArgumentDecoder(payload)

assert decoder.decode_bool() == expected