部署合约

通过内联汇编部署合约(懵点)

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
54
55
56
57
58
59
60
61
contract TextContract1{
address public owner=msg.sender;
function setOwner(address _owner)public{
require(msg.sender==owner,"not owner");
owner=_owner;
}
}

contract TestContract2{
address public owner=msg.sender;
uint public value=msg.value;
uint public x;
uint public y;
constructor(uint _x,uint _y){
x=_x;
y=_y;
}
}
//代理合约,用来部署合约1和2
contract Proxy{
event Deploy(address);
function deploy(bytes memory _code)external payable returns(address addr){//隐式返回:returns后面定义了名称,自动返回
//获得部署合约的地址
assembly{//内联汇编
//create(v,p,n)
//v代表部署合约发送的币的数量 通过callvalue获取
//p代表内存中机器码开始的位置 通过add(_code,0x20)跳跃
//n代表机器码内存的大小 通过mload(_code)获取
addr :=create(callvalue(),add(_code,0x20),mload(_code))//msg.value在这里不行

}
require(addr!=address(0),"deploy failed"); //判断是否部署成功
emit Deploy(addr);
}
//通过date来呼叫另一个合约中的函数
function execute(address _target,bytes memory _date)external payable{
(bool success, )=_target.call{value:msg.value}(_date);
require(success,"failed");
}
}


//助手合约,用来得到合约1和2或者合约中函数的code
contract Helper{
//获取呼叫合约1的代码
function getBytecode1()external pure returns(bytes memory){
bytes memory bytecode=type(TestContract1).creationCode;//特定方法type(合约名称).creationCode
return bytecode;
没有构造函数时用此方法获得bytecode;

}
//获取呼叫合约2的代码
function getBytecode2(uint _x,uint _y)external pure returns(bytes memory){
bytes memory bytecode=type(TestContract2).creationCode;//特定方法
return abi.encodePacked(bytecode,abi.encode(_x,_y)); //通过将传入的参数与bytecode打包生成新的bytecode
}
//获取呼叫合约1中setOwner的所需要的date
function getCalldate(address _owner)external pure returns(bytes memory){//_owner为传入合约1中函数的参数
return abi.encodeWithSignature("setOwner(address)",_owner);//特定方法
}
}

用create2来构造函数(可提前预测生成的地址)

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
//SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
contract DeployWithCreate2{
address public owner;
constructor(address _owner){
owner=_owner;
}
}

contract Create2Factory{
event Deploy(address addr);
function deploy(uint _salt)external{
DeployWithCreate2 _contract=new DeployWithCreate2{
salt:bytes32(_salt)
}(msg.sender);//create2方法相对于原来的方法只需加个大括号
emit Deploy(address(_contract));
}

//计算合约地址的方法
function getAddress(bytes memory bytecode,uint _salt)public view returns(address)
{
bytes32 hash=keccak256(abi.encodePacked(
bytes1(0xff),address(this),_salt,keccak256(bytecode)
));
return address(uint160(uint(hash)));

}
//计算bytecode
function getBytecode(address _owner)public pure returns(bytes memory){
bytes memory bytecode=type(DeployWithCreate2).creationCode;
return abi.encodePacked(bytecode,abi.encode(_owner));
}
}

寻找slot

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
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
contract A{
bytes32 public a;
bytes32 public b;
bytes32 public c;
uint public n;
uint public g=100 ether;
uint public f=2**256-1;
//keccak256(bytes32(1))!=keccak256(abi.encodePacked(bytes32(1)))
function Mapping(address _salt,uint num)external returns(bytes32){//_salt=1
a=keccak256(abi.encodePacked(bytes32(uint(uint160(_salt))),bytes32(num)));
return a;
}
function UInt(uint num)external returns(bytes32 ){
b=keccak256(abi.encodePacked(bytes32(num)));
return b;
}
function ToBytes(uint _a)external returns(bytes32){
c=bytes32(_a);
return c;
}
function find()external returns(uint){
n=2**256-1-uint(b)+1;
return n;
}
}

solidity汇编

Memory layout

  • 内存地址:以字节为单位:storage layout :256位一个slot
  • 0x00-0x3f:保留:0x10:16 0x20:32 0x30:48 0x40:64 //相当于演草纸(keccak时会用来保留数据)
  • 0x40-0x5f: 32个自由内存指针(初始指向0x80-0x9f然后依次向下移动指向下一位)
  • 0x60-0x7f: zero slot// 没啥用
  • 0x80-0x9f:自由指针指向以及以后的地址都是自由指针指向的地址

内存操作相关的汇编

  • Mload(offset字节): 将内存(memory)数据(32字节)载入stack(头部)
  • Mstore(offset,value): 把(memory)里的数组设置为value 语法 :mstore(0,value)
  • Sload(slotindex):语法result := sload(number.slot) 寻找对应slot的值,并将result放在堆栈中
  • Sstore(slotindex,value): 语法sstore(number.slot,value) 设置对映slot的值
  • return (offset,length):(0,32) 返回内存(memory)中的数据

联系

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
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
interface Itest{
function readData()external view returns(uint);//可查返回值,偷偷返回了
}
contract test{
uint256 number;
function store(uint num)public{
assembly{
sstore(number.slot,num)
}
}
function read()public view returns(uint256){
assembly{
let result:=sload(number.slot)//所有局部变量都在堆栈上面(result在堆栈上)

mstore(0,result)//因为return要返回内存中的数据,result在堆栈上,所以将它储存到内存中

return(0,32)//返回的是对应slot中32的长度的数据,0表示对应slot,32代表返回数据长度

}
}
function readData()public view returns(uint256){//如果没有returns仍可以返回,但需要一个返回接口如上面的接口
assembly{
let result:=sload(number.slot)
let free_pointer:=mload(0x40)//将自由指针指向40这个位置
mstore(free_pointer,result)//改变值
return(free_pointer,32)
}
}

}