这是地址类型的高级用法。
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
是不同的。