Skip to content

Commit

Permalink
feat: create the eth abi decoding
Browse files Browse the repository at this point in the history
  • Loading branch information
albertolerda authored and jaromil committed Jul 3, 2023
1 parent dd62a34 commit 3c8df4b
Show file tree
Hide file tree
Showing 3 changed files with 77 additions and 17 deletions.
42 changes: 25 additions & 17 deletions src/lua/crypto_ethereum.lua
Original file line number Diff line number Diff line change
Expand Up @@ -559,31 +559,39 @@ function ETH.contract_return_factory(params)

local res = {}
for i, v in ipairs(params) do
-- I don't check the range of values (for bool the input should be 0 or 1),
-- while for int<M> should be 0 ... 2^(<M>)-1
if v == 'address' or string.match(v, '^uint%d+$') then
table.insert(res, BIG.new(val:sub(32 * (i-1)+1, 32 * i)))
elseif v == 'bool' then
table.insert(res, BIG.new(val:sub(32 * (i-1)+1, 32 * i)) ~= BIG.new(0))
elseif v == 'string' or v == 'bytes' then
-- TODO: don't know the maximum size of argument
-- there could be an overflow
local offset = tonumber(val:sub(32 * (i-1)+1, 32 * i):hex(), 16)
local slen = tonumber(val:sub(1+offset, 32+offset):hex(), 16)
local s = val:sub(1+offset+32, offset+32+slen):string()
-- I don't check the range of values (for bool the input should be 0 or 1),
-- while for int<M> should be 0 ... 2^(<M>)-1
if v == 'address' or string.match(v, '^uint%d+$') then
local val = BIG.new(val:sub(32 * (i-1)+1, 32 * i))
if v == 'address' then
val = val:fixed(32)
end
table.insert(res, val)
elseif v == 'bool' then
table.insert(res, BIG.new(val:sub(32 * (i-1)+1, 32 * i)) ~= BIG.new(0))
elseif v == 'string' or v == 'bytes' then
-- TODO: don't know the maximum size of argument
-- there could be an overflow
local offset = tonumber(val:sub(32 * (i-1)+1, 32 * i):hex(), 16)
local slen = tonumber(val:sub(1+offset, 32+offset):hex(), 16)
local s = val:sub(1+offset+32, offset+32+slen):string()
if v == 'string' then
s = s:string()
s = s:string()
end
table.insert(res, s)
else
assert(false, "Unknown data type")
end
table.insert(res, s)
elseif v == "bytes32" then -- TODO: for any bytesXX
local val = val:sub(32 * (i-1)+1, 32 * i)
table.insert(res, val)
else
assert(false, "Unknown data type")
end
end

return res
end
end

ETH.abi_decode = ETH.contract_return_factory

-- methods with the modifier "view" have to be executed (locally) with
-- eth_call, they don't change the blockchain
Expand Down
19 changes: 19 additions & 0 deletions src/lua/zencode_ethereum.lua
Original file line number Diff line number Diff line change
Expand Up @@ -391,6 +391,25 @@ When("create the ethereum abi encoding of '' using ''", function(t, args)
new_codec('ethereum abi encoding', {encoding = 'hex'})
end)

When("create the ethereum abi decoding of '' using ''", function(t, args)
-- We imply that t is an octet/octet array and args is a single string/a string array
local data = have(t)
local o_type_spec = have(args)
local type_spec
-- TODO: support for nested array using deepmap.
if(type(o_type_spec) == "table") then
type_spec = {}
for i,v in pairs(o_type_spec) do
type_spec[i] = O.to_string(v)
end
else
type_spec = O.to_string(o_type_spec)
end
empty'ethereum abi decoding'
ACK.ethereum_abi_decoding = ETH.abi_decode(type_spec)(data)
new_codec('ethereum abi decoding', {zentype="a"})
end)

When("create the ethereum signature of ''", function(object)
local sk = havekey'ethereum'
local data = have(object)
Expand Down
33 changes: 33 additions & 0 deletions test/zencode/ethereum.bats
Original file line number Diff line number Diff line change
Expand Up @@ -853,3 +853,36 @@ EOF
save_output eth_sign_arr_eth_add_dict_out.json
assert_output '{"addresses":{"first":"0x2B8070975AF995Ef7eb949AE28ee7706B9039504","second":"0x3028806AC293B5aC9b863B685c73813626311DaD","third":"0xe1C2F1ACb2758c4D88EDb84e0306A0a96682E62a"},"signatures":["0xed8f36c71989f8660e8f5d4adbfd8f1c0288cca90d3a5330b7bf735d71ab52fe7ba0a7827dc4ba707431f1c10babd389f658f8e208b89390a9be3c097579a2ff1b","0x40d305373c648bb6b2bbadebe02ada256a9d0b3d3c37367c0a2795e367b22f7372e40dfc3497927764d1585783d058e4367bb4d24d2107777d7aa4ddcb6593c71b","0x9e07477c31db612e8c99a950385162373ff41a5b8941470b1aeba43b76c5357005fce6615567dc1944cc02fbed86202b09d92d79fbade425af0d74c328d8f6ae1c"]}'
}

@test "ABI decoding" {
cat <<EOF | save_asset 'eth_abi_decoding.data'
{
"typeSpec": [
"uint256",
"bytes32",
"uint256"
],
"encoded_data": "00000000000000000000000000000000000000000000000000000000000000c848656c6c6f20576f726c6400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000d3"
}
EOF
cat <<EOF | zexe eth_abi_decoding.zen eth_abi_decoding.data
Scenario ethereum
Given I have a 'hex' named 'encoded data'
Given I have a 'string array' named 'typeSpec'
When I create the ethereum abi decoding of 'encoded data' using 'typeSpec'
When I create the copy of element '1' in array 'ethereum abi decoding'
When I rename 'copy' to 'request_id'
When I create the copy of element '2' in array 'ethereum abi decoding'
When I rename 'copy' to 'data'
When I create the copy of element '3' in array 'ethereum abi decoding'
When I rename 'copy' to 'dao_vote_id'
Then print the 'request_id' as 'integer'
Then print the 'data' as 'hex'
Then print the 'dao_vote_id' as 'integer'
EOF
save_output 'eth_abi_decoding.json'
assert_output '{"dao_vote_id":"211","data":"48656c6c6f20576f726c64000000000000000000000000000000000000000000","request_id":"200"}'
}

0 comments on commit 3c8df4b

Please sign in to comment.