Closed nikitaeverywhere closed 2 years ago
Related: #2526
Hello! Say we have "Tether USD" string encoded in the JSON RPC response:
POST https://eth.public-rpc.com { "jsonrpc": "2.0", "id": 0, "method": "eth_call", "params": [ { "to": "0xdac17f958d2ee523a2206206994597c13d831ec7", "data": "0x06fdde03" }, "latest" ] }
{ "jsonrpc": "2.0", "id": 0, "result": "0x0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000a5465746865722055534400000000000000000000000000000000000000000000" }
The result decoding is easy in JavaScript, check this: https://codepen.io/ZitRos/pen/ExLaByJ
const res = new Web3(window.ethereum).eth.abi.decodeParameters([{ type: 'string', name: 'myString' }], '0x0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000a5465746865722055534400000000000000000000000000000000000000000000'); console.log(res[0]); // "Tether USD"
However when we try the same using EthereumAbiValue.decodeValue with
"string"
it doesn't work (returns an empty string). Uint though works well.What is wrong?
Same thing if you take this string from the test and insert it to JavaScript code: it can't decode it. You can quickly check it here.
new Web3(window.ethereum).eth.abi.decodeParameters([{type: 'string',name: 'test'}], "0x 000000000000000000000000000000000000000000000000000000000000002c48656c6c6f20576f726c64212020202048656c6c6f20576f726c64212020202048656c6c6f20576f726c64210000000000000000000000000000000000000000") // Throws an error
Can anyone suggest what is wrong with
decodeParameters
andstring
? Or how to properly decode "Tether USD" usingwallet-core
from the RPC call above?Thank you.
I do not think it's a bug, there is a confusion between decoding a parameter and a value here, the test you are pointing out is decoding a value of type string, not a full parameter including the type - if you were decoding the full parameter the result would be 0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002c48656c6c6f20576f726c64212020202048656c6c6f20576f726c64212020202048656c6c6f20576f726c64210000000000000000000000000000000000000000
source: https://abi.hashex.org/
I do think you are looking for: https://github.com/trustwallet/wallet-core/blob/1114cf79bf23d8125c717924738522669adfd77f/src/Ethereum/ABI/Parameters.h#L65
js solution:
try {
const res = new Web3(window.ethereum).eth.abi.decodeParameters([{
type: 'string',
name: 'myString'
}], '0x0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002c48656c6c6f20576f726c64212020202048656c6c6f20576f726c64212020202048656c6c6f20576f726c64210000000000000000000000000000000000000000');
document.body.textContent = res[0];
} catch (e) {
document.body.textContent = e.toString();
}
cpp solution:
TEST(EthereumAbi, EncodeParamsStringSimple) {
auto p = Parameters(std::vector<std::shared_ptr<ParamBase>>{
std::make_shared<ParamString>("Hello World! Hello World! Hello World!")});
Data encoded;
p.encode(encoded);
ASSERT_EQ(hex(encoded), "0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002c48656c6c6f20576f726c64212020202048656c6c6f20576f726c64212020202048656c6c6f20576f726c64210000000000000000000000000000000000000000");
}
Please feel free to re-open if you have any questions.
Thanks a ton @Milerius! This explanation sound to me, I spend some time to understand it. However I still struggle to understand how to parse the response from JSON PRC; decoding plain RPC response 0x0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000a5465746865722055534400000000000000000000000000000000000000000000
doesn't work, how should I transform it to be parseable?
EthereumAbiValue.decodeValue(hexStringToByteArray(encodedString), "string") // ""
To decode, one needs to know the paramter types. The eth_call returns an encoded data, and its structure depends on the contract called. So you need to know the parameter structure returned by the called contract -- this is documentation of the contract. Then construct the parameter structure, and then it can decode (like here https://github.com/trustwallet/wallet-core/blob/master/tests/Ethereum/AbiTests.cpp#L933)
It is not possible to decode without knowing upfront the order and types of the parameters.
Here's C code for decoding, a set of one string parameter:
auto p = Parameters(std::vector<std::shared_ptr<ParamBase>>{std::make_shared<ParamString>()});
size_t offset = 0;
p.decode(parse_hex("0x0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000a5465746865722055534400000000000000000000000000000000000000000000"), offset);
std::cout << "Value: '" << dynamic_cast<ParamString*>(p.getParam(0).get())->getVal() << "' \n";
@catenocrypt Is there something similar in wallet core for Android? Don't see it.
Hello! Say we have "Tether USD" string encoded in the JSON RPC response:
The result decoding is easy in JavaScript, check this: https://codepen.io/ZitRos/pen/ExLaByJ
However when we try the same using EthereumAbiValue.decodeValue with
"string"
it doesn't work (returns an empty string). Uint though works well.What is wrong?
Same thing if you take this string from the test and insert it to JavaScript code: it can't decode it. You can quickly check it here.
Can anyone suggest what is wrong with
decodeParameters
andstring
? Or how to properly decode "Tether USD" usingwallet-core
from the RPC call above?Thank you.