抱歉,您的浏览器无法访问本站
本页面需要浏览器支持(启用)JavaScript
了解详情 >

1. create

1.1 简介

概念:

智能合约可以由其他合约和普通账户利用 create操作码创建。在这两种情况下,新合约的地址都以相同的方式计算:创建者的地址(通常为部署的钱包地址或者合约地址)和nonce(该地址发送交易的总数,对于合约账户是创建的合约总数,每创建一个合约nonce+1))的哈希。

计算式:

新地址 = hash(创建者地址, nonce)

创建者地址不会变,但nonce可能会随时间而改变,因此create创建的合约地址不好预测。

2.create2

2.1 简介

create2的用法和create有点类型,同样是new一个合约,并传入新合约构造函数所需的参数,不同点在于要多传入一个salt(盐)参数:

1
Contract X = new Contract{salt: _salt, value: _value}(params);

解读:Contract是要创建的合约名,X是合约对象(address),_salt是指定的盐;如果构造函数是payable,可以在创建时传入_value数量的ETH,params是新合约构造函数的参数。

2.2 计算create2地址

注:如果需要进行合约交互,且待部署合约的构造器带参,则需要对待传参数进行abi.encode()打包,再使用 abi.encodePacked()对bytecode和abi.encode()的结果进行紧打包

如代码所示:

1
2
3
4
5
6
function getBycode() internal pure returns(bytes memory result) {
// type().creationCode 写死
bytes memory temp = type(Student).creationCode;
// 这里的参数值我写死了(Student 构造器的参数)
result = abi.encodePacked(temp, abi.encode(1,"biyou"));
}

❗❗❗abi.encodePacked(temp, abi.encode(1,"biyou")) 外层的abi.encodePacked()将不会对abi.encode(1,"biyou")的值进行紧打包了,举例如下:

代码1:

1
2
3
4
5
6
7
// 非紧打包 -- 涉及了合约构造函数的参数
function encodeBycode(uint id, string memory name) external pure returns(bytes memory result) {
bytes memory temp = type(Student).creationCode;
// 将字节码和参数进行紧打包
result = abi.encodePacked(temp, abi.encode(id,name));
}

结果1:

image-20240412172959709

代码2:

1
2
3
4
5
6
// 非紧打包 -- 涉及了合约构造函数的参数
function encodeBycode1(uint id, string memory name) external pure returns(bytes memory result) {
bytes memory temp = type(Student).creationCode;
// 将字节码和参数进行非紧打包
result = abi.encode(temp, abi.encode(id,name));
}

结果2:

image-20240412173007426

测试合约;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

// 一个用于测试的合约
contract Student {
uint256 public id ;
string public name;

constructor(uint256 _id, string memory _name) {
id = _id;
name = _name;
}

function getId() external view returns(uint256) {
return id;
}

function getName() external view returns(string memory) {
return name;
}
}

代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

// create2合约
contract create2 {

// 使用create2计算地址,我只需要改变salt(string类型)的值就可以就算出不一样的地址
function create2Address(string memory salt) external view returns(address result){
result = address(
uint160(
uint(
keccak256(abi.encodePacked(
// bytes1(0xff),
uint8(0xff), // 固定的一个字节的常数 0xff
address(this), //当前合约地址(create2合约地址)
keccak256(abi.encodePacked(salt)), //对盐进行紧打包后再进行hash
keccak256(getBycode()) //获取要计算的合约的字节码 再进行hash
))
)
)
);
}

// 使用create2计算地址,传入代部署合约的字节码,我只需要改变salt(string类型)的值就可以就算出不一样的地址
function create2Address(bytes memory bycode,string memory salt) external view returns(address result){
result = address(
uint160(
uint(
keccak256(abi.encodePacked(
// bytes1(0xff),
uint8(0xff), // 固定的一个字节的常数 0xff
address(this), //当前合约地址(create2合约地址)
keccak256(abi.encodePacked(salt)), //对盐进行紧打包
keccak256(bycode) //要计算的合约的字节码
))
)
)
);
}

// 获取部署合约的字节码(内部合约)
function getBycode() internal pure returns(bytes memory result) {
// type().creationCode 写死
bytes memory temp = type(Student).creationCode;
// 这里的参数值我写死了(Student 构造器的参数)
result = abi.encodePacked(temp, abi.encode(1,"biyou"));
}

// 通过create2部署合约,new的形式
function makeSudentByCreate2(string memory _salt, uint256 id, string memory name) external returns(Student student){
student = new Student{salt: keccak256(abi.encodePacked(_salt))}(id, name);
}
}

一个灵活一点的代码:

1
2
3
4
5
6
7
8
9
10
11
    function getCreate2Address(address addToDeploy, uint256 salt, bytes memory bycode) external pure returns(address  result) {
result = address(uint160(uint(
keccak256(abi.encodePacked(
uint8(0xff), // 固定的一个字节的常数 0xff
addToDeploy, //当前合约地址(create2合约地址)
keccak256(abi.encodePacked(salt)), //对盐进行紧打包
keccak256(bycode) //要计算的合约的字节码
))
)));
}
}

2.3 使用内联汇编

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// /* 使用内联汇编自带的 create2() */
function create2NewContractByInline(uint salt) public returns (address) {
bytes memory code = type(test).creationCode;
// 如果待部署合约的构造器中有参数,则使用如下方式进行获取code
// bytes memory code = abi.encodePacked(type().creationCode, abi.encode());
bytes32 _salt = keccak256(abi.encodePacked(salt));

address result;
assembly {
result := create2(
0, // value 表示要向新合约发送的以太币数量
add(code, 32), // 表示跳过数组长度
mload(code), // 读取code的长度
_salt // 盐
)
}
return result;
}

2.4 暴破求解create2地址

————计算出 将来的地址合约含有某个字段

操作方法 ====》计算指定合约地址(含某个字段)

相关链接

评论



政策 · 统计 | 本站使用 Volantis 主题设计