Skip to content

Instantly share code, notes, and snippets.

@islishude
Created March 6, 2020 02:16
Show Gist options
  • Save islishude/55dcb0917bcf8f62bd2ed2cc19af1597 to your computer and use it in GitHub Desktop.
Save islishude/55dcb0917bcf8f62bd2ed2cc19af1597 to your computer and use it in GitHub Desktop.
Solidity proxy with CREATE2

Complete example

pragma solidity ^0.6.2;

interface IERC20 {
    function totalSupply() external view returns (uint);
    function balanceOf(address tokenOwner) external view returns (uint balance);
    function allowance(address tokenOwner, address spender) external view returns (uint remaining);
    function transfer(address to, uint tokens) external returns (bool success);
    function approve(address spender, uint tokens) external returns (bool success);
    function transferFrom(address from, address to, uint tokens) external returns (bool success);

    event Transfer(address indexed from, address indexed to, uint tokens);
    event Approval(address indexed tokenOwner, address indexed spender, uint tokens);
}

contract Forwarder {
  address public destination;

  constructor() public {
  }

  function flushERC20(address tokenContractAddress) public {
    IERC20 tokenContract = IERC20(tokenContractAddress);
    uint256 forwarderBalance = tokenContract.balanceOf(address(this));
    tokenContract.transfer(destination, forwarderBalance);
  }
  
  function init(address _destination) public {
      require(destination == address(0x0));
      destination = _destination;
  }
}

contract ForwarderFactory {

  constructor() public {}

  function cloneForwarder(address forwarder, uint256 salt) public returns (Forwarder clonedForwarder) {
    address clonedAddress = createClone(forwarder, salt);
    clonedForwarder = Forwarder(clonedAddress);
    clonedForwarder.init(Forwarder(forwarder).destination());
  }

  function createClone(address target, uint256 salt) private returns (address result) {
    bytes20 targetBytes = bytes20(target);
    assembly {
      let clone := mload(0x40)
      mstore(clone, 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000000000000000000000)
      mstore(add(clone, 0x14), targetBytes)
      mstore(add(clone, 0x28), 0x5af43d82803e903d91602b57fd5bf30000000000000000000000000000000000)
      result := create2(0, clone, 0x37, salt)
    }
  }
}
@SimonVillage
Copy link

I was wondering why the init function is checking that the address is 0 and then you call a transfer via flushERC20 to this destination?

@islishude
Copy link
Author

@SimonHausdorf yeah, it just an example, I wrote a complete project, check out https://github.com/islishude/eth-create2-wallet

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