Created
March 31, 2018 17:32
-
-
Save wadealexc/2574ea97533a9eb7edf0e186ba715a4a to your computer and use it in GitHub Desktop.
Demonstrates a contract reading dynamic-size return data from another contract
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
pragma solidity ^0.4.21; | |
contract A { | |
address[] public addrs; | |
function A () public { | |
while (addrs.length < 10) | |
addrs.push(msg.sender); | |
} | |
function getAddrs() public view returns (address[]) { | |
return addrs; | |
} | |
} | |
contract B { | |
function getAddrs(address _a) public view returns (address[] addrs) { | |
// Function selector for 'getAddrs()' | |
bytes4 addrs_selector = bytes4(keccak256("getAddrs()")); | |
assembly { | |
// Get pointer to free memory - we'll construct calldata for getAddrs() here | |
let ptr := mload(0x40) | |
// Load getAddrs() selector into the pointer | |
mstore(ptr, addrs_selector) | |
// staticcall ensures our call does not change state | |
// Specify forwarding all gas, to address _a, and pass in 4 bytes stored at the pointer | |
// Return size is dynamic, so we don't specify a return destination or size (hence 0, 0) | |
let ret := staticcall(gas, _a, ptr, 0x04, 0, 0) | |
// If the call failed, revert | |
if iszero(ret) { revert (0, 0) } | |
// Set the location of our return array to be at the end of any accessed memory (msize returns the largest index of memory accessed so far) | |
addrs := msize | |
// Copies all of the returned data to addrs, excepting the first 32 (0x20) bytes | |
// The first 32 bytes in a dynamic return payload are a data read offset (returned data is ABI-encoded) | |
// You can read more about that here: https://solidity.readthedocs.io/en/v0.4.21/abi-spec.html | |
// The second 32 bytes will store the length of the returned array, which we want to be stored in addrs | |
// Directly after the length comes the actual data in the array | |
// [data offset][length][ind0][ind1][ind2]... | |
// Taking the above into consideration, we know: | |
// returndatasize = 64 + (32 * (array.length)) | |
returndatacopy(addrs, 0x20, sub(returndatasize, 0x20)) | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment