EIPs/EIPS/eip-2470.md
lightclient 3194278525
Switch validator to eipv (#2860)
* switch to eipv

* fix

* fix

* 1153 remove trailing whitespace

* remove file name checks

* 615 remo whitespace before comma

* 884 remove extra single-quotes

* 1337 remove whitespace before comma

* 1057 remove extra spaces after comma

* 2470 update created date to Y/M/D format

* 1078 update required eips to be in ascending order

* 2477 update required eips to be in ascending order

* 1271 remove extra whitespace

* 2767 required eipupdated to be in ascending order

* 2525 update created date to Y/M/D format

* 2458 remove trailing whitespace

* 1884 remove trailing whitespace

* 712 authors should be on a single line

* 601 remove extra whitespace

* 1485 remove unneeded parentheses

* 634 remove trailing whitespace

* 2657 update discussions-to to correct spelling

* 2009 remove trailing whitespace

* 998 required eips updated to be in ascending order

* 1186 remove trailing whitespace

* 1470 remove extra whitespace

* 1895 update created date to Y/M/D format

* 2747 remove extra whitespace

* 1613 remove leading whitespace

* 1571 can'have both handle and email in author field

* 1191 remove trailing whitespace

* 1973 remove trailing whitespace

* 196 don't wrap title field

* 1679 required eips must be in ascending order

* 1620 author can't have both handle and email

* 197 don't line wrap title field

* 2378 remove extra newline

* 1355 author can't have both handle and email

* 698 update created date to Y/M/D format

* 2193 required eips must be in ascending order

* 214 remove extra info after author email

* use v0.0.3 of eipv

* 1 remove malformed field

* bump eipv to v0.0.4

* cache eipv build

* 1485 remove extra author info

* 2771 removing extra whitespaces
2020-08-10 11:18:25 -05:00

10 KiB

eip title author discussions-to status type category created requires
2470 Singleton Factory Ricardo Guilherme Schmidt (@3esmit) https://ethereum-magicians.org/t/erc-2470-singleton-factory/3933 Draft Standards Track ERC 2020-01-15 1014

Simple Summary

Some DApps needs one, and only one, instance of an contract, which have the same address on any chain.

A permissionless factory for deploy of keyless deterministic contracts addresses based on its bytecode.

Abstract

Some contracts are designed to be Singletons which have the same address no matter what chain they are, which means that should exist one instance for all, such as EIP-1820 and EIP-2429. These contracts are usually deployed using a method known as Nick's method, so anyone can deploy those contracts on any chain and they have a deterministic address. This standard proposes the creation of a CREATE2 factory using this method, so other projects requiring this feature can use this factory in any chain with the same setup, even in development chains.

Motivation

Code reuse, using the factory becomes easier to deploy singletons.

Specification

[ERC2470] Singleton Factory

This is an exact copy of the code of the [ERC2470 factory smart contract].

pragma solidity 0.6.2;


/**
 * @title Singleton Factory (EIP-2470)
 * @notice Exposes CREATE2 (EIP-1014) to deploy bytecode on deterministic addresses based on initialization code and salt.
 * @author Ricardo Guilherme Schmidt (Status Research & Development GmbH)
 */
contract SingletonFactory {
    /**
     * @notice Deploys `_initCode` using `_salt` for defining the deterministic address.
     * @param _initCode Initialization code.
     * @param _salt Arbitrary value to modify resulting address.
     * @return createdContract Created contract address.
     */
    function deploy(bytes memory _initCode, bytes32 _salt)
        public
        returns (address payable createdContract)
    {
        assembly {
            createdContract := create2(0, add(_initCode, 0x20), mload(_initCode), _salt)
        }
    }
}
// IV is a value changed to generate the vanity address.
// IV: 6583047

Deployment Transaction

Below is the raw transaction which MUST be used to deploy the smart contract on any chain.

0xf9016c8085174876e8008303c4d88080b90154608060405234801561001057600080fd5b50610134806100206000396000f3fe6080604052348015600f57600080fd5b506004361060285760003560e01c80634af63f0214602d575b600080fd5b60cf60048036036040811015604157600080fd5b810190602081018135640100000000811115605b57600080fd5b820183602082011115606c57600080fd5b80359060200191846001830284011164010000000083111715608d57600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250929550509135925060eb915050565b604080516001600160a01b039092168252519081900360200190f35b6000818351602085016000f5939250505056fea26469706673582212206b44f8a82cb6b156bfcc3dc6aadd6df4eefd204bc928a4397fd15dacf6d5320564736f6c634300060200331b83247000822470

The strings of 2470's at the end of the transaction are the r and s of the signature. From this deterministic pattern (generated by a human), anyone can deduce that no one knows the private key for the deployment account.

Deployment Method

This contract is going to be deployed using the keyless deployment method---also known as Nick's method---which relies on a single-use address. (See Nick's article for more details). This method works as follows:

  1. Generate a transaction which deploys the contract from a new random account.
  • This transaction MUST NOT use EIP-155 in order to work on any chain.
  • This transaction MUST have a relatively high gas price to be deployed on any chain. In this case, it is going to be 100 Gwei.
  1. Forge a transaction with the following parameters:

    {
        nonce: 0,
        gasPrice: 100000000000,
        value: 0,
        data: '0x608060405234801561001057600080fd5b50610134806100206000396000f3fe6080604052348015600f57600080fd5b506004361060285760003560e01c80634af63f0214602d575b600080fd5b60cf60048036036040811015604157600080fd5b810190602081018135640100000000811115605b57600080fd5b820183602082011115606c57600080fd5b80359060200191846001830284011164010000000083111715608d57600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250929550509135925060eb915050565b604080516001600160a01b039092168252519081900360200190f35b6000818351602085016000f5939250505056fea26469706673582212206b44f8a82cb6b156bfcc3dc6aadd6df4eefd204bc928a4397fd15dacf6d5320564736f6c63430006020033',
        gasLimit: 247000,
        v: 27,
        r: '0x247000',
        s: '0x2470'
    }
    

    The r and s values, made of starting 2470, are obviously a human determined value, instead of a real signature.

  2. We recover the sender of this transaction, i.e., the single-use deployment account.

    Thus we obtain an account that can broadcast that transaction, but we also have the warranty that nobody knows the private key of that account.

  3. Send exactly 0.0247 ether to this single-use deployment account.

  4. Broadcast the deployment transaction.

    Note: 247000 is the double of gas needed to deploy the smart contract, this ensures that future changes in OPCODE pricing are unlikely to cause this deploy transction to fail out of gas. A left over will sit in the address of about 0.01 ETH will be forever locked in the single use address.

The resulting transaction hash is 0x803351deb6d745e91545a6a3e1c0ea3e9a6a02a1a4193b70edfcd2f40f71a01c.

This operation can be done on any chain, guaranteeing that the contract address is always the same and nobody can use that address with a different contract.

Single-use Factory Deployment Account

0xBb6e024b9cFFACB947A71991E386681B1Cd1477D

This account is generated by reverse engineering it from its signature for the transaction. This way no one knows the private key, but it is known that it is the valid signer of the deployment transaction.

To deploy the registry, 0.0247 ether MUST be sent to this account first.

Factory Contract Address

0xce0042B868300000d44A59004Da54A005ffdcf9f

The contract has the address above for every chain on which it is deployed.

ABI for SingletonFactory:

[
    {
        "constant": false,
        "inputs": [
            {
                "internalType": "bytes",
                "name": "_initCode",
                "type": "bytes"
            },
            {
                "internalType": "bytes32",
                "name": "_salt",
                "type": "bytes32"
            }
        ],
        "name": "deploy",
        "outputs": [
            {
                "internalType": "address payable",
                "name": "createdContract",
                "type": "address"
            }
        ],
        "payable": false,
        "stateMutability": "nonpayable",
        "type": "function"
    }
]

Rationale

SingletonFactory does not allow sending value on create2, this was done to prevent different results on the created object. SingletonFactory allows user defined salt to facilitate the creation of vanity addresses for other projects. If vanity address is not necessary, salt bytes(0) should be used. Contracts that are constructed by the SingletonFactory MUST not use msg.sender in their constructor, all variables must came through initialization data. This is intentional, as if allowing a callback after creation to aid initialization state would lead to contracts with same address (but different chains) to have the same address but different initial state. The resulting address can be calculated in chain by any contract using this formula: address(keccak256(bytes1(0xff), 0xce0042B868300000d44A59004Da54A005ffdcf9f, _salt, keccak256(_code)) << 96) or in javascript using https://github.com/ethereumjs/ethereumjs-util/blob/master/docs/README.md#const-generateaddress2.

Backwards Compatibility

Does not apply as there are no past versions of Singleton Factory being used.

Test Cases

TBD

Implementation

https://github.com/3esmit/ERC2470

Security Considerations

Some contracts can possibly not support being deployed on any chain, or require a different address per chain, that can be safely done by using comparison in EIP-1344 in constructor. Account contracts are singletons in the point of view of each user, when wallets want to signal what chain id is intended, EIP-1191 should be used. Contracts deployed on factory must not use msg.sender in constructor, instead use constructor parameters, otherwise the factory would end up being the controller/only owner of those.

Copyright and related rights waived via CC0.