Contract factories are smart contracts that create other smart contracts. Here are a few reasons you might do this.

Integrity : Children of a contract factory have deterministic code. You can expect these contracts to follow a protocol; for example, only transferring VoteTokens after the user votes.

: Children of a contract factory have deterministic code. You can expect these contracts to follow a protocol; for example, only transferring VoteTokens after the user votes. Permissions: Perhaps you want to allow only approved smart contracts to be able to call a contract method. Rather than approving them manually, the factory can approve them as they are created.

While this article will focus on Ethereum, several of its concepts will apply to other smart contract systems.

Contract Proxies

When creating a factory, consider whether the created contracts should be proxies. Proxy smart contracts do not contain their own code, and instead DELEGATECALL into a backing contract. Proxies have their own data context and, except for the gas required to DELEGATECALL, behave exactly the same as their backing contract.

The CREATE code size for a proxy is significantly smaller than a proper contract. For example, in FinneyVote the gas burned creating a proper Proposal is 635997 compared to 142248 when making a proxy, a 78% reduction.

The DELEGATECALL overhead varies according to the size of the transaction data. For small amounts of transaction data, the difference could be as low as 795 (proxy)(direct), which is necessarily less than 4% because transactions have a base cost of 21000.

Divide the CREATE savings by the expected number of transactions to calculate the target overhead. Evaluate this target overhead against the overhead expected from typical transactions. For FinneyVote, proxies create a gas savings so long as there are fewer than 621 transactions per proposal. So far, all proposals have less than 10 transactions each, so FinneyVote is encouraging use of proxies.

Your factory does not have to commit to using direct contracts or proxies; you can make both methods available and shift your default client behavior according to actual usage.

Optimizing Proxies

The smallest proxy available is Peter Murray’s CloneFactory16, which is a combination of several developers’ attempts to optimize proxy overhead and code size. My personal contribution was the savings derived from mining a backing contract with leading zeroes. With leading zeroes, your clone can use PUSH16 instead of PUSH20 when pushing the backing contract onto the stack. Using PUSH16 instead of PUSH20 reduces proxy code size by 4 bytes, or 800 gas. Each additional zero byte will require 256 times more computing power, so there are diminishing returns.

You can mine a contract with leading zeroes with MyEtherWallet’s VanityEth. If the zeroth transaction from the derived private key creates a contract, it will have the mined contract address, because contract addresses are deterministic.

vanityeth --contract -i 00000000 # 8 leading zeroes -> 4 zero-bytes

Unlike CloneFactory16, you will want to hardcode your backing contract. The backing contract for FinneyVote proposals was `0x000000005fbE2cC9B1B684ec445CaF176042348e`, which translates to the following factory method.

function proposeProxy(bytes _resolution) external returns (ProposalInterface) {

ProperProposal proposal; bytes memory clone = hex"600034603b57602f80600f833981f3600036818037808036816f5fbe2cc9b1b684ec445caf176042348e5af415602c573d81803e3d81f35b80fd"; assembly { let data := add(clone, 0x20) proposal := create(0, data, 58) } proposal.init(msg.sender, _resolution); accounts[proposal].permissions |= PROPOSAL; emit Proposal(proposal); return proposal;

}

Safety Considerations

It is important that your backing contract cannot be killed, because its death would break all of your proxies. A similar issue was behind the failure of Parity’s multi-signature wallets in November 2017. The easiest way to prevent SUICIDE is to exclude it from your code altogether. The gas refund is trivial and bounded to half of the transaction gas, so it will rarely be worth it to support contract cleanup.

It is also important to ensure that your proxy’s initializer cannot be called more than once. There are several ways to do this, but the cheapest is not to read contract state, but to verify that `msg.sender` is the factory contract. This is because SLOAD costs 200 gas, while CALLER costs only 2. As contract addresses are deterministic, your backing contract can know the factory’s address before deployment.

If I’ve left anything out, please leave a comment. Claps are also appreciated.

Update: See also EIP1167, which is standardizing the minimum proxy contract.