How to compute the CREATE2 address for a minimal proxy?

Hi Ed,

I created the following simple Minimal Proxy Factory to compute an address and deploy.

I used @tinchoabbate’s excellent deep dive to get the byte code for a minimal proxy:

I used OpenZeppelin Contracts Create2 to compute the address and to deploy.

:warning: The following code hasn’t been tested nor has it been audited

A more complete version would also include initialization of the minimal proxy
(e.g. https://github.com/OpenZeppelin/openzeppelin-sdk/blob/master/packages/lib/contracts/upgradeability/ProxyFactory.sol#L32)

MinimalProxyFactory.sol

// SPDX-License-Identifier: MIT
pragma solidity ^0.6.0;

import "@openzeppelin/contracts/utils/Create2.sol";

contract MinimalProxyFactory {
    event MinimalProxyCreated(address minimalProxy);

    function computeAddress(uint256 salt, address implementation)
        public
        view
        returns (address)
    {
        return
            Create2.computeAddress(
                keccak256(abi.encodePacked(salt)),
                keccak256(getContractCreationCode(implementation)),
                address(this)
            );
    }

    function deploy(
        uint256 salt,
        address implementation
    ) public {
        address minimalProxy = Create2.deploy(
            0,
            keccak256(abi.encodePacked(salt)),
            getContractCreationCode(implementation)
        );
        emit MinimalProxyCreated(minimalProxy);
    }

    function getContractCreationCode(address logic)
        internal
        pure
        returns (bytes memory)
    {
        bytes10 creation = 0x3d602d80600a3d3981f3;
        bytes10 prefix = 0x363d3d373d3d3d363d73;
        bytes20 targetBytes = bytes20(logic);
        bytes15 suffix = 0x5af43d82803e903d91602b57fd5bf3;
        return abi.encodePacked(creation, prefix, targetBytes, suffix);
    }
}

Box.sol

From: https://docs.openzeppelin.com/learn/developing-smart-contracts#setting-up-a-solidity-project

// contracts/Box.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.6.0;


contract Box {
    uint256 private value;

    // Emitted when the stored value changes
    event ValueChanged(uint256 newValue);

    // Stores a new value in the contract
    function store(uint256 newValue) public {
        value = newValue;
        emit ValueChanged(newValue);
    }

    // Reads the last stored value
    function retrieve() public view returns (uint256) {
        return value;
    }
}

2_deploy.js

// migrations/2_deploy.js
const Box = artifacts.require("Box");
const MinimalProxyFactory = artifacts.require("MinimalProxyFactory");

module.exports = async function (deployer) {
  await deployer.deploy(Box);
  await deployer.deploy(MinimalProxyFactory);
};

Deploy a minimal proxy

Using the factory, I compute an address, then deploy a minimal proxy and interact with it.

$ npx truffle console --network rinkeby
truffle(rinkeby)> box = await Box.deployed()
truffle(rinkeby)> factory = await MinimalProxyFactory.deployed()
truffle(rinkeby)> await factory.computeAddress(42, box.address)
'0xFa4f101C260ebFDdf98f6b3e0A159886D876Fe0B'
truffle(rinkeby)> await factory.deploy(42, box.address)
{ tx:
   '0x301f328227120e90c90bbb3ab8c23672e4cb310e3519842b1ecad29ccbed5036',
...

truffle(rinkeby)> boxProxy = await Box.at('0xFa4f101C260ebFDdf98f6b3e0A159886D876Fe0B')
truffle(rinkeby)> await boxProxy.store(7)
{ tx:
   '0x9db5a64b67281b903114e90a488440ece6a3f3a3485c676884990484d5e5ba61',
...

truffle(rinkeby)> (await boxProxy.retrieve()).toString()
'7'
1 Like