--- title: eth_call Investigation Notes --- # Input Parameters ### Block Number - latest block number ```json= // Returns output of NUMBER opcode // Code: 0x684360005260206000f360005260096017f3 // request { "jsonrpc": "2.0", "method": "eth_call", "params": [ { "from": null, "to": "{{contractAddress}}", "data":"" }, "pending" ], "id": 8 } // response { "jsonrpc": "2.0", "id": 8, "result": "0x00000000000000000000000000000000000000000000000000000000000000df" } // current block is 224 (pending) so this is the last which is 223 ``` - pending ```json= // Returns output of NUMBER opcode // Code: 0x684360005260206000f360005260096017f3 // request { "jsonrpc": "2.0", "method": "eth_call", "params": [ { "from": null, "to": "{{contractAddress}}", "data":"" }, "pending" ], "id": 8 } // response { "jsonrpc": "2.0", "id": 8, "result": "0x00000000000000000000000000000000000000000000000000000000000000c1" } // current block is 225 so this is the one in progress ``` - earliest ```json= // Returns output of NUMBER opcode // Code: 0x684360005260206000f360005260096017f3 // request { "jsonrpc": "2.0", "method": "eth_call", "params": [ { "from": null, "to": "{{contractAddress}}", "data":"" }, "earliest" ], "id": 8 } // response { "jsonrpc": "2.0", "id": 8, "result": "0x" } // earliest retrieves the genesis block ``` - mispelled ```json // Returns output of NUMBER opcode // Code: 0x684360005260206000f360005260096017f3 // request { "jsonrpc": "2.0", "method": "eth_call", "params": [ { "from": null, "to": "{{contractAddress}}", "data":"" }, "latst" ], "id": 8 } // response { "jsonrpc": "2.0", "id": 8, "error": { "code": -32602, "message": "invalid argument 1: hex string without 0x prefix" } } ``` - null or undefined ```json // Returns output of NUMBER opcode // Code: 0x684360005260206000f360005260096017f3 // request { "jsonrpc": "2.0", "method": "eth_call", "params": [ { "from": null, "to": "{{contractAddress}}", "data":"" }, null ], "id": 8 } // response { "jsonrpc": "2.0", "id": 8, "error": { "code": -32000, "message": "invalid arguments; neither block nor hash specified" } } ``` - block height (hex encoded height) - valid height ```json // Returns output of NUMBER opcode // Code: 0x684360005260206000f360005260096017f3 // request { "jsonrpc": "2.0", "method": "eth_call", "params": [ { "from": null, "to": "{{contractAddress}}", "data":"" }, "0x1" ], "id": 8 } // response { "jsonrpc": "2.0", "id": 8, "result": "0x0000000000000000000000000000000000000000000000000000000000000001" } ``` - height greater than current block ```json // Returns output of NUMBER opcode // Code: 0x684360005260206000f360005260096017f3 // request { "jsonrpc": "2.0", "method": "eth_call", "params": [ { "from": null, "to": "{{contractAddress}}", "data":"" }, "0x8" ], "id": 8 } // response { "jsonrpc": "2.0", "id": 8, "error": { "code": -32000, "message": "header not found" } } ``` ### <i>from</i> - null account ```json // Code: 0x683360005260206000f360005260096017f3 // request { "jsonrpc": "2.0", "method": "eth_call", "params": [ { "from": null, "to": "{{contractAddress}}", "data":"" }, "latest" ], "id": 8 } // response { "jsonrpc": "2.0", "id": 8, "result": "0x0000000000000000000000000000000000000000000000000000000000000000" } ``` - non-null account ```json // Code: 0x683360005260206000f360005260096017f3 // request { "jsonrpc": "2.0", "method": "eth_call", "params": [ { "from": "{{Account1}}", "to": "{{contractAddress}}", "data":"" }, "latest" ], "id": 8 } // response { "jsonrpc": "2.0", "id": 8, "result": "0x000000000000000000000000c228a058717372e08f58a113df1bdff35babd05a" } ``` - non-existent account ```json // Code: 0x683360005260206000f360005260096017f3 // request { "jsonrpc": "2.0", "method": "eth_call", "params": [ { "from": "0xc228a058718372e08f58f113df1bdff35babd05a", "to": "{{contractAddress}}", "data":"" }, "latest" ], "id": 8 } // response { "jsonrpc": "2.0", "id": 8, "result": "0x000000000000000000000000c228a058718372e08f58f113df1bdff35babd05a" } ``` - improperly formatted account - length ```json // Code: 0x683360005260206000f360005260096017f3 // request { "jsonrpc": "2.0", "method": "eth_call", "params": [ { "from": "0xc228a058718372e08f58f113dff35babd05a", "to": "{{contractAddress}}", "data":"" }, "latest" ], "id": 8 } // response { "jsonrpc": "2.0", "id": 8, "error": { "code": -32602, "message": "invalid argument 0: hex string has length 36, want 40 for common.Address" } } ``` - invalid characters ```json // Code: 0x683360005260206000f360005260096017f3 // request { "jsonrpc": "2.0", "method": "eth_call", "params": [ { "from": "0xc228a05871837#e08f58f113df1bdff35babd05a", "to": "{{contractAddress}}", "data":"" }, "latest" ], "id": 8 } // response { "jsonrpc": "2.0", "id": 8, "error": { "code": -32602, "message": "invalid argument 0: json: cannot unmarshal invalid hex string into Go struct field CallArgs.from of type common.Address" } } ``` ### <i>to</i> - null ```json // request { "jsonrpc": "2.0", "method": "eth_call", "params": [ { "from": "{{Account1}}", "to": null, "data":null }, "latest" ], "id": 8 } // response { "jsonrpc": "2.0", "id": 8, "result": "0x" } ``` - improper formatting - length ```json // request { "jsonrpc": "2.0", "method": "eth_call", "params": [ { "from": "{{Account1}}", "to": "0x91a2ac564fac17965ee2db773500fde39f0cfb", "data":null }, "latest" ], "id": 8 } // response { "jsonrpc": "2.0", "id": 8, "error": { "code": -32602, "message": "invalid argument 0: hex string has length 38, want 40 for common.Address" } } ``` - invalid characters ```json // request { "jsonrpc": "2.0", "method": "eth_call", "params": [ { "from": "{{Account1}}", "to": "0x91a2#c564fac17965ee2db77359800fde39f0cfb", "data":null }, "latest" ], "id": 8 } // response { "jsonrpc": "2.0", "id": 8, "error": { "code": -32602, "message": "invalid argument 0: json: cannot unmarshal invalid hex string into Go struct field CallArgs.to of type common.Address" } } ``` - Account doesn't exist ```json // request { "jsonrpc": "2.0", "method": "eth_call", "params": [ { "from": "{{Account1}}", "to": "0x91a2ac564fac17964ee2db77359800fde39f0cfb", "data":"" }, "latest" ], "id": 8 } // response { "jsonrpc": "2.0", "id": 8, "result": "0x" } ``` ### <i>gas</i> - output of GAS opcode - if gas is not defined ```json // code returns output of GAS opcode // code 0x685a60005260206000f360005260096017f3 // request { "jsonrpc": "2.0", "method": "eth_call", "params": [ { "from": "{{Account1}}", "to": "{{contractAddress}}", "data":null }, "latest" ], "id": 8 } // response { "jsonrpc": "2.0", "id": 8, "result": "0x00000000000000000000000000000000000000000000000000000000017d2636" } ``` - gas is defined (above limit) ```json // code returns output of GAS opcode // code 0x685a60005260206000f360005260096017f3 // request { "jsonrpc": "2.0", "method": "eth_call", "params": [ { "from": "{{Account1}}", "to": "{{contractAddress}}", "data":null, "gas": "0x33333" }, "latest" ], "id": 8 } // response { "jsonrpc": "2.0", "id": 8, "result": "0x000000000000000000000000000000000000000000000000000000000002e129" } ``` - gas is defined (below limit) ```json // code returns output of GAS opcode // code 0x685a60005260206000f360005260096017f3 // request { "jsonrpc": "2.0", "method": "eth_call", "params": [ { "from": "{{Account1}}", "to": "{{contractAddress}}", "data":null, "gas": "0x3333" }, "latest" ], "id": 8 } // response { "jsonrpc": "2.0", "id": 8, "error": { "code": -32000, "message": "err: intrinsic gas too low: have 13107, want 21000 (supplied gas 13107)" } } ``` - gas is higher implicit but below actual ```json // code returns output of GAS opcode after storing and then loading from // storage (very expensive) // 0x6e5a60005560005460005260206000f3600052600f6011f3 // request { "jsonrpc": "2.0", "method": "eth_call", "params": [ { "from": "{{Account1}}", "to": "{{contractAddress}}", "data":null, "gas": "0x5208" // exactly implicit }, "latest" ], "id": 8 } // response { "jsonrpc": "2.0", "id": 8, "error": { "code": -32000, "message": "out of gas" } } ``` - if gas is not hex encoded it will return ```jsx "error": { "code": -32602, "message": "invalid argument 0: json: cannot unmarshal hex number with leading zero digits into Go struct field CallArgs.gas of type hexutil.Uint64" } ``` - if gas is too low it will return ```jsx "error": { "code": -32000, "message": "err: intrinsic gas too low: have 1, want 21204 (supplied gas 1)" } ``` - if sufficient gas it returns ```jsx "result": "0x0000000000000000000000000000000000000000000000000000000000000002" ``` - with gas equal to anything greater than `"0xffffffffffffffff"` which is equivalent to saying that gas must be less than or equal to `2^64 - 1` ```jsx "error": { "code": -32602, "message": "invalid argument 0: json: cannot unmarshal hex number > 64 bits into Go struct field CallArgs.gas of type hexutil.Uint64" } ``` - effects on GASLIMIT - no gas set ```json // code returns output of GASLIMIT opcode // 0x684560005260206000f360005260096017f3 // request { "jsonrpc": "2.0", "method": "eth_call", "params": [ { "from": "{{Account1}}", "to": "{{contractAddress}}", "data":null }, "latest" ], "id": 8 } // response { "jsonrpc": "2.0", "id": 8, "result": "0x0000000000000000000000000000000000000000000000000000000000997eb0" // 10059440 } // the above response does not change unless a transaction is processed on-chain // (e.g. deploying another contract) ``` - gas sent (above implicit) ```json // code returns output of GASLIMIT opcode // 0x684560005260206000f360005260096017f3 // request { "jsonrpc": "2.0", "method": "eth_call", "params": [ { "from": "{{Account1}}", "to": "{{contractAddress}}", "data":null, "gas": "0x5500" }, "latest" ], "id": 8 } // response { "jsonrpc": "2.0", "id": 8, "result": "0x0000000000000000000000000000000000000000000000000000000000995852" // 10049618 } ``` ### <i>gasPrice</i> - gasPrice as null ```json // returns the output of GASPRICE opcode // 0x683a60005260206000f360005260096017f3 // request { "jsonrpc": "2.0", "method": "eth_call", "params": [ { "from": "{{Account1}}", "to": "{{contractAddress}}", "data":null, "gas": "0x5500" }, "latest" ], "id": 8 } // response { "jsonrpc": "2.0", "id": 8, "result": "0x0000000000000000000000000000000000000000000000000000000000000000" } ``` - gasPrice set - low ```json // returns the output of GASPRICE opcode // 0x683a60005260206000f360005260096017f3 // request { "jsonrpc": "2.0", "method": "eth_call", "params": [ { "from": "{{Account1}}", "to": "{{contractAddress}}", "data":null, "gas": "0x5500", "gasPrice": "0x1" }, "latest" ], "id": 8 } // response { "jsonrpc": "2.0", "id": 8, "result": "0x0000000000000000000000000000000000000000000000000000000000000001" } ``` - very high ```json // returns the output of GASPRICE opcode // 0x683a60005260206000f360005260096017f3 // request { "jsonrpc": "2.0", "method": "eth_call", "params": [ { "from": "{{Account1}}", "to": "{{contractAddress}}", "data":null, "gas": "0x5500", "gasPrice": "0x1000000000000000000000000000000000000000000000000000000000000" }, "latest" ], "id": 8 } // response { "jsonrpc": "2.0", "id": 8, "result": "0x0001000000000000000000000000000000000000000000000000000000000000" } ``` - too high ```json // returns the output of GASPRICE opcode // 0x683a60005260206000f360005260096017f3 // request { "jsonrpc": "2.0", "method": "eth_call", "params": [ { "from": "{{Account1}}", "to": "{{contractAddress}}", "data":null, "gas": "0x5500", "gasPrice": "0x10000000000000000000000000000000000000000000000000000000000000" }, "latest" ], "id": 8 } // response { "jsonrpc": "2.0", "id": 8, "error": { "code": -32000, "message": "err: insufficient funds for gas * price + value: address 0xC228a058717372E08F58a113dF1BDfF35bABD05a have 115792089237316195423570985008687907853269984665640564039357534007913129639927 want 615145474073242288187720857858654510470496793536215496459618415042038501212160 (supplied gas 21760)" } } ``` ### <i>value</i> - effect on contract BALANCE - undefined (no effect) - defined and greater than 0 ```json // code returns BALANCE of contract ACCOUNT opcode // 0x69303160005260206000f3600052600a6016f3 // request { "jsonrpc": "2.0", "method": "eth_call", "params": [ { "from": "{{Account1}}", "to": "{{contractAddress}}", "data":null, "value": "0x1" }, "latest" ], "id": 8 } // response { "jsonrpc": "2.0", "id": 8, "result": "0x0000000000000000000000000000000000000000000000000000000000000001" } ``` - very large (below value is greater than from account value) ```json // code returns BALANCE of contract ACCOUNT opcode // 0x69303160005260206000f3600052600a6016f3 // request { "jsonrpc": "2.0", "method": "eth_call", "params": [ { "from": "{{Account1}}", "to": "{{contractAddress}}", "data":null, "value": "0x1000000000000000000000000000000000000000000000000000000000000000" }, "latest" ], "id": 8 } // response { "jsonrpc": "2.0", "id": 8, "result": "0x1000000000000000000000000000000000000000000000000000000000000000" } ``` - too large ```json // code returns BALANCE of contract ACCOUNT opcode // 0x69303160005260206000f3600052600a6016f3 // request { "jsonrpc": "2.0", "method": "eth_call", "params": [ { "from": "{{Account1}}", "to": "{{contractAddress}}", "data":null, "value": "0x10000000000000000000000000000000000000000000000000000000000000000" }, "latest" ], "id": 8 } // response (if amount transfered is too large but account had enough) { "jsonrpc": "2.0", "id": 8, "error": { "code": -32602, "message": "invalid argument 0: json: cannot unmarshal hex number > 256 bits into Go struct field CallArgs.value of type *hexutil.Big" } } // reponse (if from account didn't have enough value) { "jsonrpc": "2.0", "id": 8, "error": { "code": -32000, "message": "err: insufficient funds for transfer: address 0x9fc48f3BD757d35a7c286af4735B7250b4A4929b (supplied gas 25000000)" } } ``` - from account undefined (any amount greater than 0) ```json // code returns BALANCE of contract ACCOUNT opcode // 0x69303160005260206000f3600052600a6016f3 // request { "jsonrpc": "2.0", "method": "eth_call", "params": [ { "from": null, "to": "{{contractAddress}}", "data":null, "value": "0x1000000000000000000000000000000000000000000000000000000000000000" }, "latest" ], "id": 8 } // response { "jsonrpc": "2.0", "id": 8, "error": { "code": -32000, "message": "err: insufficient funds for transfer: address 0x0000000000000000000000000000000000000000 (supplied gas 25000000)" } } ``` ### `eth_call` from accounts with too little ETH or Zero? `eth_call` succeeds despite not having enough balance ### What is TIMESTAMP? seconds since 1/1/1970 (UNIX Epoch time) of the specified block # Request format ```bash= ### Request curl -H "Content-Type: application/json" http://localhost:8545/ -X POST --data '{ "method": "eth_call", "params": [ { "from": "0x85f7c2480b66ca340e9f2a534dbf8b660137889f", "to": "0x52e596894ea366943da485eaca43f1813aac551d", "data": "0x6ffa1caa0000000000000000000000000000000000000000000000000000000000000005" }, "latest" ], "id": 1, "jsonrpc": "2.0" }' ### Response { "jsonrpc": "2.0", "id": 1, "result": "0x000000000000000000000000000000000000000000000000000000000000000a" } ``` # Call data types ## Unsigned Integers uses [08bb1114](#08bb1114) For a given call to this contract we need to first format the data request; to establish a baseline of how things work right now, here're the results from the built-in methods ```javascript= const data = await contract.methods.addAssembly(1,2).encodeABI() // the data to be sent to the contract // '0x08bb111400000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002' const res = await ethers.call({to:"<Contract Address>", data}) // '0x0000000000000000000000000000000000000000000000000000000000000003' // Can also make call with web3.js const res = await contract.methods.addAssembly(1,2).call() // '3' ``` But it's important that we understand what exactly goes into the request / is required for the `Call Data` type. ```javascript= // 1) calculate the hash of the method call const hash = web3Utils.sha3("addAssembly(uint256,uint256)") // uint256 comes from solidity types; but can be within uint8,uint16,...uint256 // hash -> '0x08bb1114a1f38d5f27cbb87d6d30555f5e86ce4cb3202bb7cef8b919a4a52301' // 2) extract the first 4 bytes of that hash and append it to 0x... const dataHeader = `0x${hash.slice(2,10)}` // dataHeader -> '0x08bb1114' // 3) hex encode each parameter and give 32 bytes of padding const hexEncoded1 = web3Utils.toHex(1).slice(2) // hexEncoded1 -> '1' const hexEncoded2 = web3Utils.toHex(2).slice(2) // hexEncoded2 -> '2' const input1 = "0".repeat(64).concat(hexEncoded1).slice(-64) // bytes1 -> '0000000000000000000000000000000000000000000000000000000000000001' const input2 = "0".repeat(64).concat(hexEncoded2).slice(-64) // bytes2 -> '0000000000000000000000000000000000000000000000000000000000000002' // 4) concat dataHeader and inputs in order to receive data const data = dataHeader.concat(input1, input2) // data -> '0x08bb111400000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002' ``` ## String uses [d8e928c](#d8e928c) The call data is encoded with the following format: ```javascript= const calldata1 = contract.methods.strAssemblyCalldata("a").encodeABI() // calldata1 -> '0xd8e928c7000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000016100000000000000000000000000000000000000000000000000000000000000' const memory1 = contract.methods.strAssemblyMemory("a").encodeABI() // memory1 -> '0xf62b2952000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000016100000000000000000000000000000000000000000000000000000000000000' const calldata2 = contract.methods.strAssemblyCalldata("aa").encodeABI() // calldata2 -> '0xd8e928c7000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000026161000000000000000000000000000000000000000000000000000000000000' // string call data can be broken into 4 parts `0x${web3Utils.sha3("strAssemblyMemory(string)").slice(2,10)}` // header -> 0xf62b2952 ? // {unknown} -> 000000000000000000000000000000000000000000000000000000000000002 "0".repeat(64).concat(web3Utils.toHex("aa".length).slice(2)).slice(-64) // string length -> 00000000000000000000000000000000000000000000000000000000000000002 web3Utils.toHex("aa").slice(2).concat("0".repeat(64)).slice(0,64) // hex encoded string -> 6161000000000000000000000000000000000000000000000000000000000000 ``` if the string is too long it will extend in increments of 64 bytes and each character is 2 bytes ```javascript= contract.methods.strAssemblyCalldata("aadddddddddddddddddddddddddddddd").encodeABI() // '0xd8e928c7000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000206161646464646464646464646464646464646464646464646464646464646464' contract.methods.strAssemblyCalldata("aaddddddddddddddddddddddddddddddd").encodeABI() // '0xd8e928c70000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002161616464646464646464646464646464646464646464646464646464646464646400000000000000000000000000000000000000000000000000000000000000' // diff -> 6400000000000000000000000000000000000000000000000000000000000000 // each character is 2 bytes contract.methods.strAssemblyMemory("a".repeat(32)).encodeABI() // '0xf62b2952000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000206161616161616161616161616161616161616161616161616161616161616161' contract.methods.strAssemblyMemory("a".repeat(64)).encodeABI() // '0xf62b29520000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000004061616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161' ``` ## Boolean uses [89a47ad8](#89a47ad8) The request encoding follows expected types ```javascript= await contract.methods.boolean(true).encodeABI() // '0x89a47ad80000000000000000000000000000000000000000000000000000000000000001' // breakdown... `0x${web3Utils.sha3("boolean(bool)").slice(2,10)}` // '0x89a47ad8' "0".repeat(64).concat(web3Utils.toHex(true).slice(2)).slice(-64) // '0000000000000000000000000000000000000000000000000000000000000001' ``` This is similarly followed in the case of 2 inputs / outputs ```javascript= await contract.methods.boolean2(true,false).encodeABI() '0xc89a4b3400000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000' // breakdown... `0x${web3Utils.sha3("boolean2(bool,bool)").slice(2,10)}` // '0xc89a4b34' "0".repeat(64).concat(web3Utils.toHex(true).slice(2)).slice(-64) // '0000000000000000000000000000000000000000000000000000000000000001' "0".repeat(64).concat(web3Utils.toHex(false).slice(2)).slice(-64) // '0000000000000000000000000000000000000000000000000000000000000000' ``` ## Signed Integers uses [291c4b98](#291c4b98) ```javascript= await contract.methods.signedInt(-1).encodeABI() // '0x291c4b98ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff' `0x${web3Utils.sha3("signedInt(int256)").slice(2,10)}` // '0x291c4b98' // "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" // above is just the inverted hex of its positive counterpart await contract.methods.addSignedInt(-2, -3).encodeABI() // '0xc37ccbd3fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd' `0x${web3Utils.sha3("addSignedInt(int256,int256)").slice(2,10)}` // '0xc37ccbd3' ``` # Return data types ## Unsigned Integers Consider a simple contract ```solidity library Assembly { function addAssembly(uint x, uint y) public pure returns (uint) { assembly { // Add some code here let result := add(x, y) mstore(0x0, result) return(0x0, 32) } } } ``` Then the response from a simple request will be ABI encoded ```javascript= const data = contract.methods.addAssembly(1,2).encodeABI(); // data -> '0x08bb111400000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002' const res = await ethers.call({to: "<Contract Address", data}); // res -> '0x0000000000000000000000000000000000000000000000000000000000000003' const hexEncoded3 = web3Utils.toHex(3).slice(2); // hexEncoded3 -> '3' const abiEncoded3 = "0x" + "0".repeat(64).concat(hexEncoded3).slice(-64); // abiEncoded3 -> '0x0000000000000000000000000000000000000000000000000000000000000003' // i.e. returns(uint256) ``` # Revert Uses [8d558b8](#8d558b8) Note that `signedInt(1) -> '0x291c4b980000000000000000000000000000000000000000000000000000000000000001' ` when called, the method reverts with the following RPC output: ```bash curl -H "Content-Type: application/json" http://localhost:8545/ -X POST --data '{"method":"eth_call","params":[{"from":"0x85f7c2480b66ca340e9f2a534dbf8b660137889f","to":"0x5d3320aaa0adf4a7665a10a4404a87b0c8805b01","data":"0x291c4b980000000000000000000000000000000000000000000000000000000000000001"},"latest"],"id":1,"jsonrpc":"2.0"}' > {"jsonrpc":"2.0","id":1,"error":{"code":-32000,"message":"execution reverted"}} ``` # Gas ### Low Gas Limit Uses [291c4b98](#291c4b98) ```javascript= await contract.methods.addSignedInt(1,1).call({ from: "<Any Non-Zero Balance Account>", gas: "200" }) ``` ```bash= ``` ### Low Account Balance Uses [291c4b98](#291c4b98) For accounts with a low or zero balance the call allows for the synthetic transactions to occur ```javascript= await contract.methods.addSignedInt(1,1).call({from: "0x72c90e03256099e1DC27DE3711F80bbdd5bE1925"}) // '2' await contract.methods.addSignedInt(1,1).call({from: "0x72c90e03256099e1DC27DE3711F80bbdd5bE1925", gas: "100000"}) // '2' await contract.methods.addSignedInt(1,1).call({from: "0x72c90e03256099e1DC27DE3711F80bbdd5bE1925", gasPrice: "200000000000000", gas: "100000"}) // '2' ``` This is also true when interfacing directly with geth RPC ```bash= curl -H "Content-Type: application/json" http://localhost:8545/ -X POST --data '{"method":"eth_call","params":[{"from":"0x09b1b5f60ae2648bb1b329354361f6bc243c3b7e","to":"0x52e596894ea366943da485eaca43f1813aac551d","data":"0x6ffa1caa0000000000000000000000000000000000000000000000000000000000000005"},"latest"],"id":1,"jsonrpc":"2.0"}' > {"jsonrpc":"2.0","id":1,"result":"0x000000000000000000000000000000000000000000000000000000000000000a"} ``` In contrast when actually executing the action it will error if the account doesn't have enough balance ```javascript= await contract.methods.addSignedInt(1,1).send({from: "0x72c90e03256099e1DC27DE3711F80bbdd5bE1925", gasPrice: "200000000000000", gas: "100000"}) // errors ``` # No Response Data ```bash {"jsonrpc":"2.0","id":1,"result":"0x"} ``` It appears that the above occurs for, if any reason, a contract returns no data; so it allows for things to fail silently Consider for instance the following bytecode `0x41` which is just the CODEBASE opcode Appendix --- # Errors ```bash= # ganache curl localhost:9545 -X POST {"method":"eth_call","params":[{"from":"0xe965c8ad2607884034e941e7f3f150c2ee9c9720","data":"0xc37ccbd300000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"}],"id":46,"jsonrpc":"2.0"} > zsh: no matches found: params:[from:0xe965c8ad2607884034e941e7f3f150c2ee9c9720] ``` ```bash= # the 'from' address has double quotes typo # geth curl -H "Content-Type: application/json" http://localhost:8545/ -X POST --data '{"method":"eth_call","params":[{"from":""0x85f7c2480b66ca340e9f2a534dbf8b660137889f"","to":"0x7cde2049b4445a73b1573e344f78c0202d63ebe7b51e64497e1ab3cfdbc32862","data":"0xc37ccbd300000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"},"latest"],"id":1,"jsonrpc":"2.0"}' > {"jsonrpc":"2.0","id":null,"error":{"code":-32700,"message":"parse error"}} ``` ```bash= # geth curl -H "Content-Type: application/json" http://localhost:8545/ -X POST --data '{"method":"eth_call","params":[{"from":"accounts[0]","to":"0x7cde2049b4445a73b1573e344f78c0202d63ebe7b51e64497e1ab3cfdbc32862","data":"0xc37ccbd300000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"},"latest"],"id":46,"jsonrpc":"2.0"}' > {"jsonrpc":"2.0","id":46,"error":{"code":-32602,"message":"invalid argument 0: json: cannot unmarshal hex string without 0x prefix into Go struct field CallArgs.from of type common.Address"}} ``` the return size must be 32, otherwise there is an overflow error (wrt to defining assembly returns in solidity) ```bash Error: data out-of-bounds (length=16, offset=32, code=BUFFER_OVERRUN, version=abi/5.0.7) at Logger.makeError (/Users/alitamoore/ethereum/node_modules/@ethersproject/logger/lib/index.js:180:21) at Logger.throwError (/Users/alitamoore/ethereum/node_modules/@ethersproject/logger/lib/index.js:189:20) at Reader._peekBytes (/Users/alitamoore/ethereum/node_modules/web3-eth-abi/node_modules/@ethersproject/abi/lib/coders/abstract-coder.js:149:24) at Reader.readBytes (/Users/alitamoore/ethereum/node_modules/web3-eth-abi/node_modules/@ethersproject/abi/lib/coders/abstract-coder.js:161:26) at Reader.readValue (/Users/alitamoore/ethereum/node_modules/web3-eth-abi/node_modules/@ethersproject/abi/lib/coders/abstract-coder.js:167:48) at NumberCoder.decode (/Users/alitamoore/ethereum/node_modules/web3-eth-abi/node_modules/@ethersproject/abi/lib/coders/number.js:49:28) { reason: 'data out-of-bounds', code: 'BUFFER_OVERRUN', length: 16, offset: 32 } ``` #### Block Enum The block enum is the second variable in the call and can only be "latest", "earliest", or "pending"; the following errors occur if this is violated - if you submit a request without a second parameter defined it'll throw an error ```bash { "jsonrpc":"2.0", "method":"eth_call", "params": [{ "from": "{{Account1}}", "to": "0xee408b2d602d94e06a9d0241cc9dc0092eed1d53" }], "id": 1 } >>>> { "jsonrpc": "2.0", "id": 1, "error": { "code": -32602, "message": "missing value for required argument 1" } } ``` - if you submit with something that is empty ```bash { "jsonrpc":"2.0", "method":"eth_call", "params": [{ "from": "{{Account1}}", "to": "0xee408b2d602d94e06a9d0241cc9dc0092eed1d53" }, ""], "id": 1 } >>>> { "jsonrpc": "2.0", "id": 1, "error": { "code": -32602, "message": "invalid argument 1: empty hex string" } } ``` - if you submit with something that's not an accepted value ```bash { "jsonrpc":"2.0", "method":"eth_call", "params": [{ "from": "{{Account1}}", "to": "0xee408b2d602d94e06a9d0241cc9dc0092eed1d53" }, "fake"], "id": 1 } >>>>> { "jsonrpc": "2.0", "id": 1, "error": { "code": -32602, "message": "invalid argument 1: hex string without 0x prefix" } } ``` # Contracts ##### 291c4b98 ```solidity= library Assembly { function signedInt(int _int) public pure returns (int) { return _int; } function addSignedInt(int _int1, int _int2) public pure returns (int) { return _int1 + _int2; } } ``` ``` ``` ##### d8e928c ```solidity= library Assembly { function strAssemblyCalldata(string calldata _str) public pure returns (string calldata) { return _str; } function strAssemblyMemory(string memory _str) public pure returns (string memory) { return _str; } } ``` ``` ``` ##### 08bb1114 ```solidity library Assembly { function addAssembly(uint x, uint y) public pure returns (uint) { assembly { // Add some code here let result := add(x, y) mstore(0x0, result) return(0x0, 32) } } } ``` ``` ``` ##### 89a47ad8 ```solidity= library Assembly { function boolean(bool _bool) public pure returns (bool) { return _bool; } function boolean2(bool _bool1, bool _bool2) public pure returns (bool, bool) { return (_bool1, _bool2); } } ``` ``` ``` ##### 8d558b8 ```solidity= library Assembly { function signedInt(int _int) public pure returns (int) { int apple = _int; revert(); // return _int; } function addSignedInt(int _int1, int _int2) public pure returns (int) { return _int1 + _int2; } } ``` ``` 0x6102a1610053600b82828239805160001a607314610046577f4e487b7100000000000000000000000000000000000000000000000000000000600052600060045260246000fd5b30600052607381538281f3fe730000000000000000000000000000000000000000301460806040526004361061005d576000357c010000000000000000000000000000000000000000000000000000000090048063291c4b9814610062578063c37ccbd314610092575b600080fd5b61007c600480360381019061007791906100f8565b6100c2565b604051610089919061016c565b60405180910390f35b6100ac60048036038101906100a79190610121565b6100cd565b6040516100b9919061016c565b60405180910390f35b600080829050600080fd5b600081836100db9190610187565b905092915050565b6000813590506100f281610254565b92915050565b60006020828403121561010a57600080fd5b6000610118848285016100e3565b91505092915050565b6000806040838503121561013457600080fd5b6000610142858286016100e3565b9250506020610153858286016100e3565b9150509250929050565b6101668161021b565b82525050565b6000602082019050610181600083018461015d565b92915050565b60006101928261021b565b915061019d8361021b565b9250817f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff038313600083121516156101d8576101d7610225565b5b817f80000000000000000000000000000000000000000000000000000000000000000383126000831216156102105761020f610225565b5b828201905092915050565b6000819050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b61025d8161021b565b811461026857600080fd5b5056fea2646970667358221220cef7a31d885883915a67926f53e4c6595dad92a6124c33b00a1fc55df8ff3a5a64736f6c63430008030033 ``` #### Custom1 This was primarily used to investigate the behavior of specific edge-case opcodes bytecode: ``` 4160005260206000a04360005260206000a03360005260206000a04460005260206000a04260005260206000a0 ``` Outputs (in logs): ```bash= 4160005260206000a0 # logs COINBASE output 4360005260206000a0 # logs NUMBER output 3360005260206000a0 # logs CALLER output 4460005260206000a0 # logs DIFFICULTY output 4260005260206000a0 # logs TIMESTAMP output 0x00000000000000000000000085f7c2480b66ca340e9f2a534dbf8b660137889f # COINBASE 0x000000000000000000000000000000000000000000000000000000000000006c # NUMBER -> 108 0x00000000000000000000000085f7c2480b66ca340e9f2a534dbf8b660137889f # CALLER 0x0000000000000000000000000000000000000000000000000000000000000002 # DIFFICULTY 0x00000000000000000000000000000000000000000000000000000000607d03db # TIMESTAMP -> 1618805723s since 1970 # once more a little bit later 0x00000000000000000000000085f7c2480b66ca340e9f2a534dbf8b660137889f # COINBASE 0x000000000000000000000000000000000000000000000000000000000000006f # NUMBER -> 111 0x00000000000000000000000085f7c2480b66ca340e9f2a534dbf8b660137889f # CALLER 0x0000000000000000000000000000000000000000000000000000000000000002 # DIFFICULTY 0x00000000000000000000000000000000000000000000000000000000607d0682 # TIMESTAMP -> 1618806402s since 1970 Unix epoch ```