How to deploy minimal proxies using ProxyFactory in Truffle?

Hi @xxs,

You don’t need to use utf8ToHex to convert your strings.
I would create the proxies in a separate script rather than in the one migration.

I have created a simple example below, where I create the proxies in truffle console:

SimpleToken.sol

pragma solidity ^0.5.0;

import "@openzeppelin/upgrades/contracts/Initializable.sol";

import "@openzeppelin/contracts-ethereum-package/contracts/token/ERC20/ERC20.sol";
import "@openzeppelin/contracts-ethereum-package/contracts/token/ERC20/ERC20Detailed.sol";

/**
 * @title SimpleToken
 * @dev Very simple ERC20 Token example, where all tokens are pre-assigned to the sender.
 * Note they can later distribute these tokens as they wish using `transfer` and other
 * `ERC20` functions.
 */
contract SimpleToken is Initializable, ERC20, ERC20Detailed {

    /**
     * @dev initialize that gives holder all of existing tokens.
     */
    function initialize(string memory name, string memory symbol, address holder) public initializer {
        ERC20Detailed.initialize(name, symbol, 18);
        _mint(holder, 1000000 * (10 ** uint256(decimals())));
    }
}

SimpleTokenFactory.sol

pragma solidity ^0.5.3;

import "@openzeppelin/upgrades/contracts/upgradeability/ProxyFactory.sol";

contract SimpleTokenFactory is ProxyFactory {
    address[] public tokens;

    event TokenCreated(address indexed tokenAddress);

    function createToken(address logic, string calldata name, string calldata symbol, address holder) external {

        bytes memory payload = abi.encodeWithSignature("initialize(string,string,address)", name, symbol, holder);

        // Deploy minimal proxy
        address token = deployMinimal(logic, payload);
        emit TokenCreated(token);

        tokens.push(token);
    }
}

2_deploy.js

I only deploy the logic contract and the factory.
Minimal proxies can be created via a script or the console

const SimpleToken = artifacts.require("SimpleToken");
const SimpleTokenFactory = artifacts.require("SimpleTokenFactory");

module.exports = async function (deployer) {
  await deployer.deploy(SimpleToken);
  await deployer.deploy(SimpleTokenFactory);
};

Deploy

$ npx truffle migrate

Compiling your contracts...
===========================
> Compiling ./contracts/Migrations.sol
> Compiling ./contracts/SimpleToken.sol
> Compiling ./contracts/SimpleTokenFactory.sol
> Compiling @openzeppelin/contracts-ethereum-package/contracts/GSN/Context.sol
> Compiling @openzeppelin/contracts-ethereum-package/contracts/math/SafeMath.sol
> Compiling @openzeppelin/contracts-ethereum-package/contracts/token/ERC20/ERC20.sol
> Compiling @openzeppelin/contracts-ethereum-package/contracts/token/ERC20/ERC20Detailed.sol
> Compiling @openzeppelin/contracts-ethereum-package/contracts/token/ERC20/IERC20.sol
> Compiling @openzeppelin/upgrades/contracts/Initializable.sol
> Compiling @openzeppelin/upgrades/contracts/cryptography/ECDSA.sol
> Compiling @openzeppelin/upgrades/contracts/upgradeability/BaseAdminUpgradeabilityProxy.sol
> Compiling @openzeppelin/upgrades/contracts/upgradeability/BaseUpgradeabilityProxy.sol
> Compiling @openzeppelin/upgrades/contracts/upgradeability/InitializableAdminUpgradeabilityProxy.sol
> Compiling @openzeppelin/upgrades/contracts/upgradeability/InitializableUpgradeabilityProxy.sol
> Compiling @openzeppelin/upgrades/contracts/upgradeability/Proxy.sol
> Compiling @openzeppelin/upgrades/contracts/upgradeability/ProxyFactory.sol
> Compiling @openzeppelin/upgrades/contracts/upgradeability/UpgradeabilityProxy.sol
> Compiling @openzeppelin/upgrades/contracts/utils/Address.sol
> Artifacts written to /home/abcoathup/projects/forum/xxs/build/contracts
> Compiled successfully using:
   - solc: 0.5.16+commit.9c3226ce.Emscripten.clang



Starting migrations...
======================
> Network name:    'development'
> Network id:      1596177951625
> Block gas limit: 6721975 (0x6691b7)


1_initial_migration.js
======================

   Deploying 'Migrations'
   ----------------------
   > transaction hash:    0xbdfc268046175ecac57a5c478995178dda88769035299d4d2b92a351c3f0a340
   > Blocks: 0            Seconds: 0
   > contract address:    0xe78A0F7E598Cc8b0Bb87894B0F60dD2a88d6a8Ab
   > block number:        1
   > block timestamp:     1596177963
   > account:             0x90F8bf6A479f320ead074411a4B0e7944Ea8c9C1
   > balance:             99.9967165
   > gas used:            164175 (0x2814f)
   > gas price:           20 gwei
   > value sent:          0 ETH
   > total cost:          0.0032835 ETH


   > Saving migration to chain.
   > Saving artifacts
   -------------------------------------
   > Total cost:           0.0032835 ETH


2_deploy.js
===========

   Deploying 'SimpleToken'
   -----------------------
   > transaction hash:    0x2f449545e91f8f82878c54ed59b81de9a2d720a09d21d4547da2da2d2eb7ae11
   > Blocks: 0            Seconds: 0
   > contract address:    0xCfEB869F69431e42cdB54A4F4f105C19C080A601
   > block number:        3
   > block timestamp:     1596177963
   > account:             0x90F8bf6A479f320ead074411a4B0e7944Ea8c9C1
   > balance:             99.96726942
   > gas used:            1430013 (0x15d1fd)
   > gas price:           20 gwei
   > value sent:          0 ETH
   > total cost:          0.02860026 ETH


   Deploying 'SimpleTokenFactory'
   ------------------------------
   > transaction hash:    0xd61d6304698eb95d8ef5ea817119f8e2fb9d4124ea184b42653dda06195a2c9b
   > Blocks: 0            Seconds: 0
   > contract address:    0x254dffcd3277C0b1660F6d42EFbB754edaBAbC2B
   > block number:        4
   > block timestamp:     1596177963
   > account:             0x90F8bf6A479f320ead074411a4B0e7944Ea8c9C1
   > balance:             99.92872796
   > gas used:            1927073 (0x1d67a1)
   > gas price:           20 gwei
   > value sent:          0 ETH
   > total cost:          0.03854146 ETH


   > Saving migration to chain.
   > Saving artifacts
   -------------------------------------
   > Total cost:          0.06714172 ETH


Summary
=======
> Total deployments:   3
> Final cost:          0.07042522 ETH

Create and interact with minimal proxies

$ npx truffle console
truffle(development)> logic = await SimpleToken.deployed()
truffle(development)> factory = await SimpleTokenFactory.deployed()
truffle(development)> await factory.createToken(logic.address, "Token A", "TKA", accounts[0])
truffle(development)> await factory.createToken(logic.address, "Token B", "TKB", accounts[0])
truffle(development)> tokenA = await SimpleToken.at(await factory.tokens(0))
truffle(development)> tokenB = await SimpleToken.at(await factory.tokens(1))
truffle(development)> await tokenA.name()
'Token A'
truffle(development)> await tokenB.name()
'Token B'

You also had a separate question about what does npx oz deploy kind `minimal do.
This creates minimal proxies using the OpenZeppelin CLI.

Please find below a deployment of the SimpleToken as a minimal proxy using the CLI.

$ npx oz deploy
✓ Compiling contracts with Truffle, using settings from truffle.js file
Truffle output:

Compiling your contracts...
===========================
> Compiling ./contracts/Migrations.sol
> Compiling ./contracts/SimpleToken.sol
> Compiling ./contracts/SimpleTokenFactory.sol
> Compiling @openzeppelin/contracts-ethereum-package/contracts/GSN/Context.sol
> Compiling @openzeppelin/contracts-ethereum-package/contracts/math/SafeMath.sol
> Compiling @openzeppelin/contracts-ethereum-package/contracts/token/ERC20/ERC20.sol
> Compiling @openzeppelin/contracts-ethereum-package/contracts/token/ERC20/ERC20Detailed.sol
> Compiling @openzeppelin/contracts-ethereum-package/contracts/token/ERC20/IERC20.sol
> Compiling @openzeppelin/upgrades/contracts/Initializable.sol
> Compiling @openzeppelin/upgrades/contracts/cryptography/ECDSA.sol
> Compiling @openzeppelin/upgrades/contracts/upgradeability/BaseAdminUpgradeabilityProxy.sol
> Compiling @openzeppelin/upgrades/contracts/upgradeability/BaseUpgradeabilityProxy.sol
> Compiling @openzeppelin/upgrades/contracts/upgradeability/InitializableAdminUpgradeabilityProxy.sol
> Compiling @openzeppelin/upgrades/contracts/upgradeability/InitializableUpgradeabilityProxy.sol
> Compiling @openzeppelin/upgrades/contracts/upgradeability/Proxy.sol
> Compiling @openzeppelin/upgrades/contracts/upgradeability/ProxyFactory.sol
> Compiling @openzeppelin/upgrades/contracts/upgradeability/UpgradeabilityProxy.sol
> Compiling @openzeppelin/upgrades/contracts/utils/Address.sol
> Artifacts written to /home/abcoathup/projects/forum/xxs/build/contracts
> Compiled successfully using:
   - solc: 0.5.16+commit.9c3226ce.Emscripten.clang


? Choose the kind of deployment minimal
? Pick a network development
? Pick a contract to deploy SimpleToken
Minimal proxy support is still experimental.
✓ Added contract SimpleToken
✓ Contract SimpleToken deployed
All implementations have been deployed
? Call a function to initialize the instance after creating it? Yes
? Select which function * initialize(name: string, symbol: string, holder: address)
? name: string: My Token
? symbol: string: TKN
? holder: address: 0x90F8bf6A479f320ead074411a4B0e7944Ea8c9C1
✓ Instance created at 0x3408fb50BEeEF75145EC4a51Ba819cb7c71d2732
✓ Deployed ProxyFactory at 0x59d3631c86BbE35EF041872d502F218A39FBa150
To upgrade this instance run 'oz upgrade'
0x3408fb50BEeEF75145EC4a51Ba819cb7c71d2732

We can now interact with the token using call and send-tx

$ npx oz call
? Pick a network development
? Pick an instance SimpleToken at 0x3408fb50BEeEF75145EC4a51Ba819cb7c71d2732
? Select which function name()
✓ Method 'name()' returned: My Token
My Token
1 Like