Skip to content

Instantly share code, notes, and snippets.

@mikec
Created April 17, 2018 19:48
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mikec/3ffbab8036b4913e66909d2b6eca7a74 to your computer and use it in GitHub Desktop.
Save mikec/3ffbab8036b4913e66909d2b6eca7a74 to your computer and use it in GitHub Desktop.
pragma solidity ^0.4.19;
/**
* @title Proxy
* @dev Gives the possibility to delegate any call to a foreign implementation.
*/
contract Proxy {
/**
* @dev Tells the address of the implementation where every call will be delegated.
* @return address of the implementation to which it will be delegated
*/
function implementation() public view returns (address);
/**
* @dev Fallback function allowing to perform a delegatecall to the given implementation.
* This function will return whatever the implementation call returns
*/
function () public payable {
address _impl = implementation();
require(_impl != address(0));
bytes memory data = msg.data;
assembly {
/*
delegatecall params explained:
gas: the amount of gas to provide for the call. `gas` is an Opcode that gives
us the amount of gas still available to execution
_impl: address of the contract to delegate to
add(data, 0x20): memory pointer to the start of `bytes memory data`. The 0x20 (32 bytes)
needs to be added because the first 32 bytes of the dynamic `bytes` type
contains the size of the data. This skips the first 32 bytes slot, and
points to the start of the actual data.
This param is the pointer to the `in` data. delegatecall will pass along data
from here, plus the `insize` (next param)
mload(data): loads the size of `bytes memory data`, which is in the first 32 byte slot.
mload takes a pointer (data is a pointer to the beginning of data) and reads
the 32 bytes of memory after the pointer.
This param is the `insize`, or the amount of data from `in` that delegate call
will pass along.
0, 0: These are for the `out` and `outsize` params. Because the output could be dynamic,
these are set to 0, 0 so the output data will not be written to memory. The output
data will be read using `returndatasize` and `returdatacopy` instead.
result: This will be 0 if the call fails and 1 if it succeeds
*/
let result := delegatecall(gas, _impl, add(data, 0x20), mload(data), 0, 0)
/*
`returndatasize` is an Opcode that gives us the size of the last return data. In this case, that is the size of the data returned from delegatecall
*/
let size := returndatasize
/*
0x40 is the "free memory slot", meaning a pointer to next slot of empty memory. mload(0x40)
loads the data in the free memory slot, so `ptr` is a pointer to the next slot of empty
memory. It's needed because we're going to write the return data of delegatecall to the
free memory slot.
*/
let ptr := mload(0x40)
/*
`returndatacopy` is an Opcode that copies the last return data to a slot. `ptr` is the
slot it will copy to, 0 means copy from the beginning of the return data, and size is
the amount of data to copy.
*/
returndatacopy(ptr, 0, size)
/*
if `result` is 0, revert.
if `result` is 1, return `size` amount of data from `ptr`. This is the data that was
copied to `ptr` from the delegatecall return data
*/
switch result
case 0 { revert(ptr, size) }
default { return(ptr, size) }
}
}
}
@rstormsf
Copy link

could you point out what needs to be added ?

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