Create

create在用的時候主要是根據

  1. sender address
  2. sender address’s nonce

這兩個東西來產生address

產生的公式如下

keccak256(rlp.encode(senderAddress, senderAddressNonce))[12:]

go-ethereum(v1.9.23)裡面是這樣實作的

// CreateAddress creates an ethereum address given the bytes and the nonce
func CreateAddress(b common.Address, nonce uint64) common.Address {
	data, _ := rlp.EncodeToBytes([]interface{}{b, nonce})
	return common.BytesToAddress(Keccak256(data)[12:])
}

Create2

後來新加入的opcode,擺脫了nonce的限制,讓address可以更加靈活的被運用。像是可以有如BTC一般產生一堆收款地址,等待想要回收時,再自己部署一個合約的code回收那些錢即可。create2的必要元素如下:

  1. sender address
  2. the hash of byte code being deployed
  3. a random salt (32 byte string), supplied by the creator
keccak256(0xff ++ deployingAddr ++ salt ++ keccak256(bytecode))[12:]

go-ethereum(v1.9.23)裡面是這樣實作的

// CreateAddress2 creates an ethereum address given the address bytes, initial
// contract code hash and a salt.
func CreateAddress2(b common.Address, salt [32]byte, inithash []byte) common.Address {
	return common.BytesToAddress(Keccak256([]byte{0xff}, b.Bytes(), salt[:], inithash)[12:])
}

以下有一個solidity的使用方法,可以在remix操作看看,理論上在create2Addr得到的address,用相同的參數放進去create2裡面會得到一樣的address

// SPDX-License-Identifier: MIT

pragma solidity 0.7.5;

contract Card {
    uint8 public _point;
    constructor(uint8 point) {
        _point = point;
    }
}

contract Factory {
    function create(uint8 point) external returns (address) {
        Card card = new Card(point);
        return address(card);
    }

	// example salt: 0x0000000000000000000000000000000000000000000000000000000000000001
    function create2(bytes32 salt, uint8 point) external returns (address) {
        Card card = new Card{salt: salt}(point);
        return address(card);
    }

    function create2Addr(bytes32 salt, uint8 point) external view returns (address) {
        return address(uint(keccak256(abi.encodePacked(
            byte(0xff),
            address(this),
            salt,
            keccak256(abi.encodePacked(
                type(Card).creationCode,
                abi.encode(point)  // 這裡這樣寫是因為需要padding uint8,如果傳參剛好是32byte就不用額外的abi.encode
            ))
        ))));
    }
}