0%

solidity | call 和 delegatecall

这是地址类型的高级用法。

calldelegatecall 可以调用合约地址上的函数。

  • call()
    • addr.call(函数名称,参数)
    • .value() 附加以太币 addr.call.value(y)() 等价于 addr.transfer(y)
    • gas() 指定 gas
  • delegatecall()
    • 不支持 .value()

调用失败并不会发生异常。


call


案例一

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
pragma solidity ^0.4.18;

contract Test{

uint public N;
address public sender;

function set_N(uint a){
N = a;
sender = msg.sender;
}


}

contract TestMain{

function callN(address s,uint N){
bytes4 method = bytes4(keccak256("set_N(uint256)"));
s.call(method,N);
}
}

上面调用 TestMaincallN 方法,其中

  • address s
    • Test 部署后的合约地址

调用之后,TestsenderTestMain 的合约地址。

案例二

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
pragma solidity ^0.4.18;

contract Test{

uint public N;
address public sender;

function set_N(uint a){
N = a;
sender = msg.sender;
}

function get_balance()public constant returns (uint256){
return this.balance;
}


}

contract TestMain{

constructor() public payable{}

function callN(address s,uint N){
bytes4 method = bytes4(keccak256("set_N(uint256)"));
s.call.value(1 ether)(method,N);
}
}

上面这个合约在运行的时候

s.call.value(1 ether)(method,N);

这句话是错误的,但是,运行的时候并不会发生异常。

如果想要抛出异常,可以改成

require(s.call.value(1 ether)(method,N));

上面之所以出现错误,是因为 Testset_N 要接受以太币的时候,需要加 payable ,改成下面的内容。

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
pragma solidity ^0.4.18;

contract Test{

uint public N;
address public sender;

function set_N(uint a) payable{
N = a;
sender = msg.sender;
}

function get_balance()public constant returns (uint256){
return this.balance;
}


}

contract TestMain{

constructor() public payable{}

function callN(address s,uint N){
bytes4 method = bytes4(keccak256("set_N(uint256)"));
require(s.call.value(1 ether)(method,N));
}
}

如果要指定 gas 可以

require(s.call.value(1 ether).gas(3000)(method,N));

delegatecall


delegatecallcall 的区别在于

  • 没有 value() 但是,可以附加 gas()

delegatecall 的上下文是本身,也就是调用其他合约的方法,但是,改变的是自身的参数。

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
pragma solidity ^0.4.18;

contract Test{

uint public N;
address public sender;

function set_N(uint a) payable{
N = a;
sender = msg.sender;
}

function get_balance()public constant returns (uint256){
return this.balance;
}


}

contract TestMain{

uint public N;
address public sender;

constructor() public payable{}

function callN(address s,uint N){
bytes4 method = bytes4(keccak256("set_N(uint256)"));
require(s.delegatecall(method,N));
}
}

上面调用 TestMaincallN 修改的是 TestMainNsender

并且,TestMainsender 是调用 TestMain 账户的地址,这个和 callsender 是不同的。

请我喝杯咖啡吧~