As a developer or contributor visiting the address page for a contract that has already been verified, I want to see the "Read Smart Contract" tab so I can click on it and interact with the blockchain through read-only functions.
stateMutability: view) without required arguments is shown with the following fields:query, a section with the query response is shown with the following format:[ <name> method Response ]<type> : <response>
abi saved inSmartContract table to list functions and constants;ethereum_jsonrpc for theeth_call method so that we can get the values of the blockchain;eth_call call, according to documentation;eth_call call;eth_call for the respective contract function in abi;Hey, @acravenho! We have just added more details to this card, but we still have some questions we are investigating... If you could help us with some of them, we'd appreciate it!
stateMutability: pure?1) The data is not indexed. We will need to interact with the blockchain for every read.
2) It is possible for there to be no read. I don't think we should be showing a tab in this case.
The last 3 we will need to do more research on.
About the last point, I came up with a way to do it. The function name, its arguments' types and the arguments themselves must be encoded. In order to get a value from a contract function, we use the eth_call JSON RPC method. In the data parameter, we join the following in a single string:
For instance, suppose we want to get the result for the function multiply(uint x, uint y), passing 2 and 3 as arguments. The data parameter should be created like this:
0x;multiply(uint256) to get c6888fa159d67f77c2f3d7a402e199802766bd7e8d4d1ecd2274fc920265d56a and take the first 4 bytes, ending up with c6888fa1."0000000000000000000000000000000000000000000000000000000000000002". Convert 3 to a 64 bytes hexadecimal value and get "0000000000000000000000000000000000000000000000000000000000000003" . Concatenate both hexadecimals. The data parameter is the concatenation of 1, 2 and 3:
0xc6888fa100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000003.
After doing some research, the most feasible way I found to accomplish 2 in Elixir is using this keccak lib. It is important to use {:keccakf1600, "~> 2.0", hex: :keccakf1600_orig} instead of what is in their GitHub page because the GitHub page version is the standandard implementation of the sha3 algorythm, whereas the EVM implements another one (see more on Which cryptographic hash function does Ethereum use?). So, in order to get the above full hash, we could run the following Elixir code: :keccakf1600.sha3_256("multiply(uint256)") |> Base.encode16(case: :lower). To get just the four bytes, we could do something like:
<< first_four_bytes :: binary-size(4) >> <> _remaining_bytes = :keccakf1600.sha3_256("double(int256)")
Base.encode16(first_four_bytes, case: :lower)
# "c6888fa1"
The best way I could come up to accomplish 3 in Elixir was using the Hexate lib. So, if we want to get 2 in a 64 bytes hexadecimal value, we can run: Hexate.encode(3, 64). Hexate would also be useful to decode the result that comes from the JSON RPC call response.
I found no way of accomplishing that with just the code that is currently available in this project. In fact, the Ethereumex lib does not implement it as well. I actually found an issue on its repository that actually helped me reach this solution.
What do you guys think about it? Can you think of any better apporach/solution? I personally feel that might be a native Elixir way to do what Hexate does, but I was unable to find it.
@josevalim pointed out that Hexate's implementation is actually pretty simple and there is no need to include it in the project. Reference implementation: https://github.com/rjsamson/hexate/blob/master/lib/hexate.ex#L33.
Regarding the functions sorting, I've been searching a little bit about that and found out the following:
This issue in Solidity is discussing this topic and a possible less arbitrary sorting method: https://github.com/ethereum/solidity/issues/2731
Think we can follow with the same solution used by Etherscan for now... wdyt, @acravenho?
Yes, let's follow the same format as Etherscan.
@Lucasnar regarding the last question we've listed above, the Solidity documentation on contracts says the following:
Functions can be declared pure in which case they promise not to read from or modify the state.
So, probably we should look at ABI entries with both stateMutability: pure and stateMutability: view (there is a topic in the documentation on this type too).
Also, I've tested this on Kovan and Etherscan has listed the pure function in the read tab along with the view ones.
The pure functions, since they don't read from state, could be cached and might even be able to get their value from the chain as we index the creation code.
@KronicDeth I'm not sure we can cache them. I understood they don't depend on the state, but they might depend on input arguments. For instance, the documentation example is the following one:
contract C {
function f(uint a, uint b) public pure returns (uint) {
return a * (b + 42);
}
}
It is possible to memoize a function based on its arguments. It is one of the nice things about pure functions. Whether we should do it would be if a pure call is costly, but popular with users, so it can wait until an actual performance issue is spotted.
@amandasposito @Lucasnar I found the following issues:
[x] Can't interact with methods that receive int arguments (not uint). Nothing happens once I click on Query.
[x] Addresses outputs are not displayed correctly: the word address gets a link to an invalid page and the address hash has what seems to be invalid characters. Testing with the following contract 0xb3cc76f5dd155c39169cc988d1b0e8226158c9aa gives me the result in the image below:

[x] Addresses outputs have the link anchor on the word address instead of on the address hash (in the image above, you can see that the anchor is on the word)
[x] Can't load the Read Contract tab when the contract has getters that return strings (tried this one)
[x] Some exceptions in the Solidity code don't seem to be correctly handled and, as an effect of that, the user receives no feedback. Steps to reproduce:
a) Verify this contract in Sokol 0x595b5cb47c1eca5a61f23dd5ea0d2d0bf2e95d1b,
b) Visit the Read Contract tab.
c) Fill addresses to the parameters of the function tokens and click on Query.
d) On Etherscan, it returns uint256:0, but I've noticed in the console that the following error is thrown: (RuntimeError) Data overflow encoding uint, data "0x6937cb25eb54bc013b9c13c47ab38eb63edd1493". On Remix, a different error is shown in the console: call to EtherDelta.balanceOf errored: Error encoding arguments: SyntaxError: Unexpected token x in JSON at position 48.
Most helpful comment
It is possible to memoize a function based on its arguments. It is one of the nice things about pure functions. Whether we should do it would be if a pure call is costly, but popular with users, so it can wait until an actual performance issue is spotted.