General proxy for calling external contract functions and returning their output. This is unsafe, work in progress.
pragma solidity ^0.4.24; | |
contract PipeProxy { | |
function proxy( | |
address _to, | |
bytes input_bytes, | |
uint256 gas_value | |
) | |
payable | |
public | |
returns (bytes) | |
{ | |
uint256 value = msg.value; | |
bytes memory output; | |
uint256 output_len; | |
assembly { | |
let zero_mem_pointer := 0x80 | |
let input_size := mload(input_bytes) | |
let input_ptr := add(zero_mem_pointer, 32) | |
let result := call( | |
gas_value, // gas limit | |
_to, // contract address to call | |
value, // value of transferred ETH | |
input_ptr, // inputs are stored at location input_ptr | |
input_size, // input size | |
0, // store output at pointer 0x0 | |
0 // expected output size set to 0, because we will use returndatasize | |
) | |
output_len := returndatasize | |
} | |
output = new bytes(output_len); | |
assembly { | |
// copy return data content after output length (first 32 bytes) | |
returndatacopy(add(output, 32), 0, output_len) | |
} | |
return output; | |
} | |
} | |
contract TestPipeProxy { | |
PipeProxy pipe_proxy; | |
address test_contract; | |
constructor (address _pipe_proxy, address _test_contract) public { | |
pipe_proxy = PipeProxy(_pipe_proxy); | |
test_contract = _test_contract; | |
} | |
function m_addr() view public returns(bytes32 addr) { | |
bytes4 signature = bytes4(keccak256("m_addr()")); | |
bytes memory input = abi.encodePacked(signature); | |
bytes memory answer = pipe_proxy.proxy(test_contract, input, 70000); | |
assembly { | |
addr := mload(add(answer, 32)) | |
} | |
} | |
function s_addr() view public returns(bytes32 addr) { | |
bytes4 signature = bytes4(keccak256("s_addr()")); | |
bytes memory input = abi.encodePacked(signature); | |
bytes memory answer = pipe_proxy.proxy(test_contract, input, 70000); | |
assembly { | |
addr := mload(add(answer, 32)) | |
} | |
} | |
function addr_addr() view public returns(bytes32 addr1, bytes32 addr2) { | |
bytes4 signature = bytes4(keccak256("addr_addr()")); | |
bytes memory input = abi.encodePacked(signature); | |
bytes memory answer = pipe_proxy.proxy(test_contract, input, 70000); | |
assembly { | |
addr1 := mload(add(answer, 32)) | |
addr2 := mload(add(answer, 64)) | |
} | |
} | |
function m_uint(uint256 value) view public returns(bytes32 val) { | |
bytes4 signature = bytes4(keccak256("m_uint(uint256)")); | |
bytes memory input = abi.encodeWithSelector(signature, value); | |
bytes memory answer = pipe_proxy.proxy(test_contract, input, 70000); | |
assembly { | |
val := mload(add(answer, 32)) | |
} | |
} | |
function s_uint() view public returns(bytes32 val) { | |
bytes4 signature = bytes4(keccak256("s_uint()")); | |
bytes memory input = abi.encodeWithSelector(signature); | |
bytes memory answer = pipe_proxy.proxy(test_contract, input, 70000); | |
assembly { | |
val := mload(add(answer, 32)) | |
} | |
} | |
function addr_uint() view public returns(bytes32 addr, bytes32 val) { | |
bytes4 signature = bytes4(keccak256("addr_uint()")); | |
bytes memory input = abi.encodeWithSelector(signature); | |
bytes memory answer = pipe_proxy.proxy(test_contract, input, 70000); | |
assembly { | |
addr := mload(add(answer, 32)) | |
val := mload(add(answer, 64)) | |
} | |
} | |
function m_uint_arr(uint256[4] uint_arr) view public returns(bytes32[4] arr_val) { | |
bytes4 signature = bytes4(keccak256("m_uint_arr(uint256[4])")); | |
bytes memory input = abi.encodeWithSelector(signature, uint_arr); | |
bytes memory answer = pipe_proxy.proxy(test_contract, input, 70000); | |
bytes32 val; | |
for (uint256 i = 1; i <= uint_arr.length; i++) { | |
assembly { | |
val := mload(add(answer, mul(32, i))) | |
} | |
arr_val[i - 1] = val; | |
} | |
} | |
function dynamic_uint_arr(uint256 value) public returns(uint256[] arr_val) { | |
bytes4 signature = bytes4(keccak256("dynamic_uint_arr(uint256)")); | |
bytes memory input = abi.encodeWithSelector(signature, value); | |
bytes memory answer = pipe_proxy.proxy(test_contract, input, 70000); | |
uint256 array_length; | |
uint256 val; | |
uint256 offset; | |
assembly { | |
// first 32 bytes are answer length | |
// next 32 bytes are offset | |
// then we have the array length | |
array_length := mload(add(answer, 64)) | |
} | |
arr_val = new uint256[](array_length); | |
for (uint256 i = 0; i < array_length; i++) { | |
offset = 96 + 32*i; | |
assembly { | |
val := mload(add(answer, offset)) | |
} | |
arr_val[i] = val; | |
} | |
return arr_val; | |
} | |
} | |
contract TestFunctions { | |
address public addr; | |
uint256 public tvar = 10; | |
uint256[] public arr = [1, 2, 3]; | |
struct TStruct { | |
uint256 tvar1; | |
address addr1; | |
} | |
constructor() { | |
addr = msg.sender; | |
} | |
function m_addr() view public returns(address) { | |
return msg.sender; | |
} | |
function s_addr() view public returns(address) { | |
return addr; | |
} | |
function addr_addr() view public returns(address, address) { | |
return (msg.sender, addr); | |
} | |
function m_uint(uint256 value) view public returns(uint256) { | |
return value; | |
} | |
function s_uint() view public returns(uint256) { | |
return tvar; | |
} | |
function addr_uint() view public returns(address, uint256) { | |
return (addr, tvar); | |
} | |
function m_uint_arr(uint256[4] uint_arr) view public returns(uint256[4]) { | |
return uint_arr; | |
} | |
function dynamic_uint_arr(uint256 value) public returns(uint256[]) { | |
arr.push(value); | |
return arr; | |
} | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment