Skip to content

Instantly share code, notes, and snippets.

@izqui
Last active October 21, 2021 04:24
Show Gist options
  • Star 22 You must be signed in to star a gist
  • Fork 3 You must be signed in to fork a gist
  • Save izqui/7f904443e6d19c1ab52ec7f5ad46b3a8 to your computer and use it in GitHub Desktop.
Save izqui/7f904443e6d19c1ab52ec7f5ad46b3a8 to your computer and use it in GitHub Desktop.
Very cheap to deploy (66k gas) forwarder contracts that can clone any contract and still have their own storage
// Bytecode origin https://www.reddit.com/r/ethereum/comments/6ic49q/any_assembly_programmers_willing_to_write_a/dj5ceuw/
// Modified version of Vitalik's https://www.reddit.com/r/ethereum/comments/6c1jui/delegatecall_forwarders_how_to_save_5098_on/
// Credits to Jordi Baylina for this way of deploying contracts https://gist.github.com/jbaylina/e8ac19b8e7478fd10cf0363ad1a5a4b3
// Forwarder is slightly modified to only return 256 bytes (8 normal returns)
// Deployed Factory in Kovan: https://kovan.etherscan.io/address/0xaebc118657099e2110c90494f48b3d21329b23eb
// Example of a Forwarder deploy using the Factory: https://kovan.etherscan.io/tx/0xe995dd023c8336685cb819313d933ae8938009f9c8c0e1af6c57b8be06986957
// Just 66349 gas per contract
pragma solidity ^0.4.12;
contract ForwardFactory {
function createForwarder(address target) returns (address fwdContract) {
bytes32 b1 = 0x602e600c600039602e6000f33660006000376101006000366000730000000000; // length 27 bytes = 1b
bytes32 b2 = 0x5af41558576101006000f3000000000000000000000000000000000000000000; // length 11 bytes
uint256 shiftedAddress = uint256(target) * ((2 ** 8) ** 12); // Shift address 12 bytes to the left
assembly {
let contractCode := mload(0x40) // Find empty storage location using "free memory pointer"
mstore(contractCode, b1) // We add the first part of the bytecode
mstore(add(contractCode, 0x1b), shiftedAddress) // Add target address
mstore(add(contractCode, 0x2f), b2) // Final part of bytecode
fwdContract := create(0, contractCode, 0x3A) // total length 58 dec = 3a
switch extcodesize(fwdContract) case 0 { invalid() }
}
ForwarderDeployed(fwdContract, target);
}
event ForwarderDeployed(address forwarderAddress, address targetContract);
}
@SilentCicero
Copy link

This is nice, you may also want to add a general forwarding method as well, see the uPort proxy.

@chriseth
Copy link

chriseth commented Jul 4, 2017

Please use switch extcodesize(fwdContract) case 0 { invalid() } for line 25 since jumpi will be deprecated soon.

@izqui
Copy link
Author

izqui commented Jul 5, 2017

Oh thanks @chriseth, just modified it!

@GriffGreen
Copy link

Wow!! This is cool! Nice work!

@GNSPS
Copy link

GNSPS commented Feb 18, 2018

Created an updated version of this proxy factory. The proxy now reverts instead of throwing and the factory can call the created contract right after creation. 😄
Thank you for the inspiration @izqui.

https://gist.github.com/GNSPS/ba7b88565c947cfd781d44cf469c2ddb

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