Skip to content

Commit 2c493d4

Browse files
authored
feat: argument decoder (#147)
1 parent 155502a commit 2c493d4

File tree

3 files changed

+88
-8
lines changed

3 files changed

+88
-8
lines changed
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import binascii
2+
from crypto.utils.abi_decoder import AbiDecoder
3+
4+
class ArgumentDecoder:
5+
def __init__(self, hex_string: str):
6+
try:
7+
self.bytes = binascii.unhexlify(hex_string)
8+
except binascii.Error:
9+
self.bytes = b''
10+
11+
def decode_string(self) -> str:
12+
value, _ = AbiDecoder.decode_string(self.bytes, 0)
13+
14+
return value
15+
16+
def decode_address(self) -> str:
17+
value, _ = AbiDecoder.decode_address(self.bytes, 0)
18+
19+
return value
20+
21+
def decode_unsigned_int(self) -> int:
22+
value, _ = AbiDecoder.decode_number(self.bytes, 0, False)
23+
24+
return value
25+
26+
def decode_signed_int(self) -> int:
27+
value, _ = AbiDecoder.decode_number(self.bytes, 0, True)
28+
29+
return value
30+
31+
def decode_bool(self) -> bool:
32+
value, _ = AbiDecoder.decode_bool(self.bytes, 0)
33+
return value

crypto/utils/abi_decoder.py

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -64,32 +64,36 @@ def decode_parameter(self, bytes_data, offset, param):
6464
if match:
6565
signed = match.group(1) == 'int'
6666
bits = int(match.group(2))
67-
return self.decode_number(bytes_data, offset, bits, signed)
67+
return self.decode_number(bytes_data, offset, signed)
6868
if type_ == 'tuple':
6969
return self.decode_tuple(bytes_data, offset, param)
7070
raise Exception('Unsupported type: ' + type_)
7171

72-
def decode_address(self, bytes_data, offset):
72+
@staticmethod
73+
def decode_address(bytes_data, offset):
7374
data = bytes_data[offset:offset+32]
7475
address_bytes = data[12:32]
7576
address = '0x' + address_bytes.hex()
7677
address = get_checksum_address(address)
7778
return address, 32
7879

79-
def decode_bool(self, bytes_data, offset):
80+
@staticmethod
81+
def decode_bool(bytes_data, offset):
8082
data = bytes_data[offset:offset+32]
8183
value = int.from_bytes(data, byteorder='big') != 0
8284
return value, 32
8385

84-
def decode_number(self, bytes_data, offset, bits, signed):
86+
@staticmethod
87+
def decode_number(bytes_data, offset, signed):
8588
data = bytes_data[offset:offset+32]
8689
value = int.from_bytes(data, byteorder='big', signed=signed)
8790
return value, 32
8891

89-
def decode_string(self, bytes_data, offset):
90-
data_offset = self.read_uint(bytes_data, offset)
92+
@classmethod
93+
def decode_string(cls, bytes_data, offset):
94+
data_offset = cls.read_uint(bytes_data, offset)
9195
string_offset = offset + data_offset
92-
length = self.read_uint(bytes_data, string_offset)
96+
length = cls.read_uint(bytes_data, string_offset)
9397
string_data = bytes_data[string_offset+32:string_offset+32+length]
9498
value = string_data.decode('utf-8')
9599
return value, 32
@@ -140,6 +144,7 @@ def decode_tuple(self, bytes_data, offset, param):
140144
values[name] = value
141145
return values, 32
142146

143-
def read_uint(self, bytes_data, offset):
147+
@staticmethod
148+
def read_uint(bytes_data, offset):
144149
data = bytes_data[offset:offset+32]
145150
return int.from_bytes(data, byteorder='big')
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
from crypto.utils.abi.argument_decoder import ArgumentDecoder
2+
3+
4+
def test_it_should_decode_address():
5+
payload = '000000000000000000000000512F366D524157BcF734546eB29a6d687B762255'
6+
expected = '0x512F366D524157BcF734546eB29a6d687B762255'
7+
8+
decoder = ArgumentDecoder(payload)
9+
10+
assert decoder.decode_address() == expected
11+
12+
def test_it_should_decode_unsigned_int():
13+
payload = '000000000000000000000000000000000000000000000000016345785d8a0000'
14+
expected = 100000000000000000
15+
16+
decoder = ArgumentDecoder(payload)
17+
18+
assert decoder.decode_unsigned_int() == expected
19+
20+
def test_it_should_decode_signed_int():
21+
payload = '000000000000000000000000000000000000000000000000016345785d8a0000'
22+
expected = 100000000000000000
23+
24+
decoder = ArgumentDecoder(payload)
25+
26+
assert decoder.decode_signed_int() == expected
27+
28+
def test_it_should_decode_bool_as_true():
29+
payload = '0000000000000000000000000000000000000000000000000000000000000001'
30+
expected = True
31+
32+
decoder = ArgumentDecoder(payload)
33+
34+
assert decoder.decode_bool() == expected
35+
36+
def test_it_should_decode_bool_as_false():
37+
payload = '0000000000000000000000000000000000000000000000000000000000000000'
38+
expected = False
39+
40+
decoder = ArgumentDecoder(payload)
41+
42+
assert decoder.decode_bool() == expected

0 commit comments

Comments
 (0)