Skip to content

Commit e6d97e8

Browse files
committed
Refactor abi encoding and decoding
1 parent a6a78cd commit e6d97e8

3 files changed

Lines changed: 92 additions & 8 deletions

File tree

example/storage.py

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,7 @@
2828

2929
if args.action == 'set':
3030
user = pleth.wallet.Wallet(int(args.prikey, 0))
31-
data = pleth.abi.function_selector('set', ['uint256']) + pleth.abi.argument_encoding([
32-
pleth.abi.Uint256.encode(42),
33-
])
31+
data = pleth.abi.function_selector('set', ['uint256']) + pleth.abi.argument_encoding([pleth.abi.Uint256], [42])
3432
hash = user.contract_exec(bytearray.fromhex(args.addr[2:]), 0, data)
3533
print(f'hash = 0x{hash.hex()}')
3634

pleth/abi.py

Lines changed: 65 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,12 @@ def function_selector(name: str, args_type: list[str]) -> bytearray:
1515
return pleth.core.hash(bytearray(s.encode()))[:4]
1616

1717

18-
def argument_encoding(data: list[bytearray]) -> bytearray:
19-
s = bytearray()
20-
for e in data:
21-
s.extend(e)
22-
return s
18+
def argument_decoding(args_type: list, data: bytearray) -> list:
19+
return Tuple(args_type).decode(io.BytesIO(data))
20+
21+
22+
def argument_encoding(args_type: list, args: list) -> bytearray:
23+
return Tuple(args_type).encode(args)
2324

2425

2526
class Address:
@@ -32,6 +33,10 @@ def encode(cls, origin: bytearray) -> bytearray:
3233
assert len(origin) == 20
3334
return bytearray(12) + origin
3435

36+
@classmethod
37+
def size(cls) -> int:
38+
return 32
39+
3540

3641
class Bytes:
3742
@classmethod
@@ -46,6 +51,10 @@ def encode(cls, origin: bytearray) -> bytearray:
4651
padded = (length + 31) & -32
4752
return Uint256.encode(length) + origin + bytearray(padded - length)
4853

54+
@classmethod
55+
def size(cls) -> int:
56+
return 0
57+
4958

5059
class String:
5160
@classmethod
@@ -56,6 +65,53 @@ def decode(cls, reader: io.IOBase) -> str:
5665
def encode(cls, origin: str) -> bytearray:
5766
return Bytes.encode(bytearray(origin.encode()))
5867

68+
@classmethod
69+
def size(cls) -> int:
70+
return 0
71+
72+
73+
class Tuple:
74+
def __init__(self, kype: list) -> None:
75+
self.kype = kype
76+
self.slen = 0
77+
size_list = [k.size() for k in kype]
78+
if all([s != 0 for s in size_list]):
79+
self.slen = sum(size_list)
80+
81+
def decode(self, reader: io.IOBase) -> list:
82+
muts = []
83+
vals = []
84+
for k in self.kype:
85+
match k.size():
86+
case 0:
87+
muts.append(len(vals))
88+
vals.append(Uint256.decode(reader))
89+
case _:
90+
vals.append(k.decode(reader))
91+
for i in muts:
92+
vals[i] = self.kype[i].decode(reader)
93+
return vals
94+
95+
def encode(self, origin: list) -> bytearray:
96+
assert len(origin) == len(self.kype)
97+
offs = 0
98+
for k in self.kype:
99+
offs += 32 if k.size() == 0 else k.size()
100+
head = bytearray()
101+
tail = bytearray()
102+
for k, v in zip(self.kype, origin):
103+
e = k.encode(v)
104+
match k.size():
105+
case 0:
106+
head.extend(Uint256.encode(offs + len(tail)))
107+
tail.extend(e)
108+
case _:
109+
head.extend(e)
110+
return head + tail
111+
112+
def size(self) -> int:
113+
return self.slen
114+
59115

60116
class Uint256:
61117
@classmethod
@@ -67,3 +123,7 @@ def encode(cls, origin: int) -> bytearray:
67123
assert origin >= 0
68124
assert origin <= 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
69125
return bytearray(origin.to_bytes(32, 'big'))
126+
127+
@classmethod
128+
def size(cls) -> int:
129+
return 32

test/test_abi.py

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import io
2+
import pleth
3+
4+
5+
def test_tuple():
6+
k = pleth.abi.Tuple([
7+
pleth.abi.Uint256,
8+
pleth.abi.Tuple([pleth.abi.Uint256, pleth.abi.Uint256]),
9+
pleth.abi.String,
10+
pleth.abi.String,
11+
])
12+
v = [0x123, [0x456, 0x789], '1234567890', 'Hello, world!']
13+
assert k.decode(io.BytesIO(bytes(k.encode(v)))) == v
14+
15+
16+
def test_tuple_erc20_name():
17+
k = pleth.abi.Tuple([pleth.abi.String])
18+
v = bytearray([
19+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
20+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20,
21+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
22+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08,
23+
0x55, 0x53, 0x44, 0x20, 0x43, 0x6f, 0x69, 0x6e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
24+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
25+
])
26+
assert k.decode(io.BytesIO(v))[0] == 'USD Coin'

0 commit comments

Comments
 (0)