Skip to content

Instantly share code, notes, and snippets.

@jparklev
Created March 16, 2022 05:30
Show Gist options
  • Save jparklev/4b151f4064f3cd3d28a55f5eead66f19 to your computer and use it in GitHub Desktop.
Save jparklev/4b151f4064f3cd3d28a55f5eead66f19 to your computer and use it in GitHub Desktop.
contract Store {
mapping(bytes4 => uint256) public store;
function set(bytes4 key, uint256 value) external {
store[key] = value;
}
function get(bytes4 key) external returns (uint256) {
return store[key];
}
}
contract Mock {
address public immutable impl;
Store public immutable store;
constructor(address _impl) public {
impl = _impl;
store = new Store();
}
function set(bytes4 sig, uint256 ret) public {
store.set(sig, ret);
}
fallback() payable external {
bytes4 sig = msg.sig;
uint256 value = store.get(sig);
if (value != 0) {
value = value == type(uint256).max ? 0 : value;
bytes memory res = abi.encode(value);
assembly {
return(add(0x20, res), mload(res))
}
}
address implementation = impl;
assembly {
// Copy msg.data. We take full control of memory in this inline assembly
// block because it will not return to Solidity code. We overwrite the
// Solidity scratch pad at memory position 0.
calldatacopy(0, 0, calldatasize())
// Call the implementation.
// out and outsize are 0 because we don't know the size yet.
let result := delegatecall(gas(), implementation, 0, calldatasize(), 0, 0)
// Copy the returned data.
returndatacopy(0, 0, returndatasize())
switch result
// delegatecall returns 0 on error.
case 0 {
revert(0, returndatasize())
}
default {
return(0, returndatasize())
}
}
}
}
@jparklev
Copy link
Author

Override specific method selectors (given that they return units), and proxy everything else to the "implementation" contract.

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