Nesse artigo iremos aprender a como pré-computar um endereço de contrato antes de ser implantado na blockchain.
Pré-computar um endereço
O endereço do contrato pode ser pré-computado, antes que o contrato seja implantado, usando create2
// SPDX-License-Identifier: MITpragma solidity ^0.8.13;contract Factory {// Retorna o endereço do contrato recém-implantadofunction 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 como parâmetro// https://docs.soliditylang.org/en/latest/control-structures.html#salted-contract-creations-create2return address(new TestContract{salt: _salt}(_owner, _foo));}}// Esta é a maneira mais antiga de fazer isso usando assemblycontract FactoryAssembly {event Deployed(address addr, uint salt);// 1. Obtenha o bytecode do contrato a ser implantado// NOTA: _owner e _foo são argumentos do construtor do TestContractfunction 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. Calcule o endereço do contrato a ser implantado// NOTA: _salt é um número aleatório usado para criar um endereçofunction getAddress(bytes memory bytecode, uint _salt)publicviewreturns (address){bytes32 hash = keccak256(abi.encodePacked(bytes1(0xff), address(this), _salt, keccak256(bytecode)));// NOTA: converter os últimos 20 bytes de hash para endereçarreturn address(uint160(uint(hash)));}// 3. Implantar 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 computado acima.function deploy(bytes memory bytecode, uint _salt) public payable {address addr;/*NOTA: Como chamar create2create2(v, p, n, s)criar novo contrato com código na memória p para p + ne envia v weie retorna o novo endereçowhere new address = first 20 bytes of keccak256(0xff + address(this) + s + keccak256(mem[p…(p+n)))s = big-endian 256-bit value*/assembly {addr := create2(callvalue(), // wei enviado com a chamada atual// O código real começa após pular os primeiros 32 bytesadd(bytecode, 0x20),mload(bytecode), // Carregar o tamanho do código contido nos primeiros 32 bytes_salt // Salt dos argumentos da 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;}}