Skip to content

Instantly share code, notes, and snippets.

@wadealexc
Created March 31, 2018 17:32
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save wadealexc/2574ea97533a9eb7edf0e186ba715a4a to your computer and use it in GitHub Desktop.
Save wadealexc/2574ea97533a9eb7edf0e186ba715a4a to your computer and use it in GitHub Desktop.
Demonstrates a contract reading dynamic-size return data from another contract
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