Endereço de Contrato pré-computado com Create2

# Endereço de Contrato pré-computado com Create2

O endereço do contrato pode ser pré-calculado, antes que o contrato seja implantado, usando create2

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

contract Factory {
    // Retorna o endereço do contrato recém-implantado
    function deploy(
        address _owner,
        uint _foo,
        bytes32 _salt
    ) public payable returns (address) {
        // Esta sintaxe é uma nova maneira de invocar create2 sem assembly, você só precisa passar salt
        // https://docs.soliditylang.org/en/latest/control-structures.html#salted-contract-creations-create2
        return address(new TestContract{salt: _salt}(_owner, _foo));
    }
}

// Esta é a maneira mais antiga de fazer isso usando assembly
contract FactoryAssembly {
    event Deployed(address addr, uint salt);

    // 1. Obtenha o bytecode do contrato a ser implantado
    // NOTA: _owner e _foo são argumentos do constructor TestContract
    function getBytecode(address _owner, uint _foo) public pure returns (bytes memory) {
        bytes memory bytecode = type(TestContract).creationCode;

        return abi.encodePacked(bytecode, abi.encode(_owner, _foo));
    }

    // 2. Calcular o endereço do contrato a ser implantado
    // NOTA: _salt é um número aleatório usado para criar um endereço
    function getAddress(bytes memory bytecode, uint _salt)
        public
        view
        returns (address)
    {
        bytes32 hash = keccak256(
            abi.encodePacked(bytes1(0xff), address(this), _salt, keccak256(bytecode))
        );

        // NOTA: converta os últimos 20 bytes de hash para o endereço
        return address(uint160(uint(hash)));
    }

    // 3. Implanta o contrato
    // NOTA:
    // Verifique o log de eventos Deployed que contém o endereço do TestContract implantado.
    // O endereço no log deve ser igual ao endereço calculado acima.
    function deploy(bytes memory bytecode, uint _salt) public payable {
        address addr;

        /*
        NOTA: Como criar create2

        create2(v, p, n, s)
        cria um novo contrato com código na memória p para p + n
        e envia v wei
        e retorna o novo endereço
        onde novo endereço = primeiros 20 bytes de keccak256(0xff + address(this) + s + keccak256(mem[p…(p+n)))
              s = valor big-endian 256-bit
        */
        assembly {
            addr := create2(
                callvalue(), // wei enviado com a chamada atual
                //O código real começa após pular os primeiros 32 bytes
                add(bytecode, 0x20),
                mload(bytecode), // Carregar o tamanho do código contido nos primeiros 32 bytes
                _salt // Salt dos argumentos de função
            )

            if iszero(extcodesize(addr)) {
                revert(0, 0)
            }
        }

        emit Deployed(addr, _salt);
    }
}

contract TestContract {
    address public owner;
    uint public foo;

    constructor(address _owner, uint _foo) payable {
        owner = _owner;
        foo = _foo;
    }

    function getBalance() public view returns (uint) {
        return address(this).balance;
    }
}

# Teste no Remix

Last Updated: 23/01/2024 16:25:48