这是地址类型的高级用法。
call 和 delegatecall 可以调用合约地址上的函数。
call()
addr.call(函数名称,参数)
.value() 附加以太币 addr.call.value(y)() 等价于 addr.transfer(y)
gas() 指定 gas
delegatecall()
调用失败并不会发生异常。
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); } }
|
上面调用 TestMain 的 callN 方法,其中
调用之后,Test 的 sender 为 TestMain 的合约地址。
案例二
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));
上面之所以出现错误,是因为 Test 的 set_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
delegatecall 和 call 的区别在于
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)); } }
|
上面调用 TestMain 的 callN 修改的是 TestMain 的 N 和 sender。
并且,TestMain 的 sender 是调用 TestMain 账户的地址,这个和 call 的 sender 是不同的。