Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

If Contract has been Verified, Developer sees “Read Smart Contract” tab #70

Closed
5 tasks done
acravenho opened this issue Mar 19, 2018 · 12 comments · Fixed by #279
Closed
5 tasks done

If Contract has been Verified, Developer sees “Read Smart Contract” tab #70

acravenho opened this issue Mar 19, 2018 · 12 comments · Fixed by #279

Comments

@acravenho
Copy link
Contributor

acravenho commented Mar 19, 2018

Description

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.

Acceptance Criteria

  • When the explorer user accesses the SC address page for a verified address, she will see the "Read Smart Contract" tab.
    • If the contract has no read-only functions, the tab shouldn't be shown.
  • When the user clicks on the tab, the list of read-only functions (stateMutability: view) without required arguments is shown with the following fields:
    • index
    • name
    • current value
      • If the value type is an address, the value should be formatted as a link
    • value type
  • If the read-only function requires arguments, the following fields are shown:
    • index
    • name
    • input field (placeholder: argument name and type)
      • If the function requires more than one argument, the input fields are listed side by side.
    • query button
    • return type (on a line below it)
  • If the user fills a value and clicks on query, a section with the query response is shown with the following format:
    • [ <name> method Response ]
    • <type> : <response>
      • if the response value is an address, it should be formatted as a link
      • if the response is an error, the raised message is shown.

Example

Example

screen shot 2018-03-18 at 9 13 41 pm

Tasks

  • Use abi saved in SmartContract table to list functions and constants;
  • Create call in ethereum_jsonrpc for the eth_call method so that we can get the values of the blockchain;
  • Encode the function name and arguments to the eth_call call, according to documentation;
  • Decode the response of the eth_call call;
  • Display the response of the call eth_call for the respective contract function in abi;
@gfreh
Copy link

gfreh commented Jun 6, 2018

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!

@acravenho
Copy link
Contributor Author

  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.

@gfreh gfreh moved this from To Do to Ready to Do in Developers Section Jun 7, 2018
@lucasnar
Copy link
Contributor

lucasnar commented Jun 7, 2018

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:

  1. The value "0x";
  2. The first 4 bytes of the hash of the function name with its arguments type (generated using Keccak256).
  3. If the function does not receive arguments, we don't need this third step. If it does, then we take the parameters we want to pass, and, for each one, we convert it to hexadecimal and make it 64 bytes long, concatenating them.

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:

  1. Start with 0x;
  2. Use Keccak256 on the string multiply(uint256) to get c6888fa159d67f77c2f3d7a402e199802766bd7e8d4d1ecd2274fc920265d56a and take the first 4 bytes, ending up with c6888fa1.
  3. Convert 2 to a 64 bytes hexadecimal value and get "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.

@lucasnar
Copy link
Contributor

lucasnar commented Jun 7, 2018

@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.

@lucasnar lucasnar moved this from Ready to Do to In progress in Developers Section Jun 11, 2018
@lucasnar lucasnar self-assigned this Jun 11, 2018
@ghost ghost added the in progress label Jun 12, 2018
@gfreh
Copy link

gfreh commented Jun 13, 2018

Regarding the functions sorting, I've been searching a little bit about that and found out the following:

  1. Etherscan lists the read functions using the same order as they appear in the ABI JSON.
  2. The order in the ABI JSON is determined by the order of elements in the AST (which depends on the Solidity version, btw)

This issue in Solidity is discussing this topic and a possible less arbitrary sorting method: ethereum/solidity#2731

Think we can follow with the same solution used by Etherscan for now... wdyt, @acravenho?

@acravenho
Copy link
Contributor Author

Yes, let's follow the same format as Etherscan.

@gfreh
Copy link

gfreh commented Jun 13, 2018

@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.

@KronicDeth
Copy link
Contributor

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.

@gfreh
Copy link

gfreh commented Jun 13, 2018

@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);
    }
}

@KronicDeth
Copy link
Contributor

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 amandasposito self-assigned this Jun 19, 2018
@amandasposito amandasposito moved this from In progress to Ready for QA in Developers Section Jul 4, 2018
@gfreh gfreh moved this from Ready for QA to QA in Developers Section Jul 4, 2018
@gfreh
Copy link

gfreh commented Jul 5, 2018

@amandasposito @lucasnar I found the following issues:

  • Can't interact with methods that receive int arguments (not uint). Nothing happens once I click on Query.

  • 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:

screen shot 2018-07-05 at 15 01 44

  • 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)

  • Can't load the Read Contract tab when the contract has getters that return strings (tried this one)

  • 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.

@acravenho acravenho added priority: high High priority issues and removed Kuala Lumpur labels Jul 18, 2018
@acravenho acravenho added this to the Kuala Lumpur milestone Jul 18, 2018
Developers Section automation moved this from QA to Done Jul 19, 2018
@ghost ghost removed the in progress label Jul 19, 2018
jcortejoso pushed a commit to jcortejoso/blockscout that referenced this issue Jan 20, 2020
…inspec

Get Genesis info from generic chainfile
shellteo pushed a commit to shellteo/blockscout that referenced this issue Jul 26, 2023
@SurenFTN
Copy link

Hey there I am recieving an error for Read-only function which mutability is View an it is not tacking any args . https://sahara.ftnscan.com/address/0x385C32d00cD8FF896eCd7Ca3335bb30f391a3057/read-contract#address-tabs
Here you can see the issue with two methods get_deposit_count(), get_deposit_root(), Error: (-32602) invalid argument 0: hex string has length 0, want 40 for common.Address

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
Development

Successfully merging a pull request may close this issue.

6 participants