BTC或许是加密数字货币之王,但ETH也有着自己最友善的头衔——最受欢迎数字代币平台。ETH作为一个公共区块链平台,具备着开源的智能合约功能,许多的代币发行通过ETH进行,而代币常见的是ETH上一个遵守着ERC20规范的智能合约。
假如一个ETH智能合约能够实现下面的接口,那此智能合约就是一个ERC20代币。
// ----------------------------------------------------------------------------
// ERC Token Standard #20 Interface
// https://github.com/ethereum/EIPs/blob/master/EIPS/eip-20-token-standard.md
// ----------------------------------------------------------------------------
contract ERC20Interface {
function totalSupply() public constant returns (uint);
function balanceOf(address tokenOwner) public constant returns (uint balance);
function allowance(address tokenOwner, address spender) public constant returns (uint remaining);
function transfer(address to, uint tokens) public returns (bool success);
function approve(address spender, uint tokens) public returns (bool success);
function transferFrom(address from, address to, uint tokens) public returns (bool success);
event Transfer(address indexed from, address indexed to, uint tokens);
event Approval(address indexed tokenOwner, address indexed spender, uint tokens);
}
显而易见的是,ERC20规范里仅仅存在点对点转账的transfer和transferFrom,现实情况下可能存在要向1000-10000个地址转账的情况,那我们就要生成上万个transfer交易,不得不考虑这样的效率太低了。
因此,许多ERC20代币都能够实现批量转账的接口。
例如一则爆出漏洞的BEC(https://etherscan.io/address/0xc5d105e63711398af9bbff092d4b6769c82f793d#code)就实现了batchTransfer函数。
SMT(https://etherscan.io/address/0x55f93985431fc9304077687a35a1ba103dc1e081#code)也实现了allocateTokens函数。
上述这些都能够实现一笔ETH交易完成对多个账户的代币转账或初始化的场景。
文章中提及了一种完成一对多转账的方法,这个方法被称之为transferMultiple
第一步,文中里默认已采用SafeMath库
然后,transferMultiple
transferMultiple完成了从msg.sender向count个_tos地址转账的场景,同时_tos[i]得到_values[i]的代币。
首先,进行对于第1个for循环的前置检查,从而保证每个_tos地址都为非0的地址,另外,还需要计算转账的总额,并将其录入到total变量里。在运算操作时,为避免溢出,可以采用SafeMath库,值得注意的是,每一次都要对当前计算出来的总额total和上一笔总额total_prev进行对比,从而保证total大于等于total_prev,双重校验不会整数溢出避免导致出现转账故障的情况。
其次,对于第2个for循环采用修改内部变量,但不调用transfer的方法。原因在于之前已经做了前置检查,倘若再调用transfer函数的话,程序会执行额外的没有必要的前置检查,这样会对gas增加消耗。
function transferMultiple(address[] _tos, uint256[] _values, uint count) payable public returns (bool success) {
uint256 total = 0;
uint256 total_prev = 0;
uint i = 0;
for(i=0;i<count;i++){ require(_tos[i]="" !="address(0));" total_prev="total;" total="SafeMath.add(total," _values[i]);="" require(total="">= total_prev);
}
require(total <= balanceOf(msg.sender);
for(i=0;i<=count-1;i++){
balances[msg.sender] = SafeMath.sub(balances[msg.sender], _values[i]);
balances[_tos[i]] = SafeMath.add(balances[_tos[i]], _values[i]);
Transfer(msg.sender, _tos[i], _values[i]);
//上面的3行可改为下1行,它的优点在于无需假设用户的剩余资产存储在类型为mapping的balances这个变量中,它的劣势是会额外增加一些没有必要的前置检查,导致额外消耗gas
//transfer(_tos[i], _values[i]);
}
return true;
}
此时,相信各位比较在意的是,用transferMultiple一次完成1对10000转账能否成功?
从测试可以显示,1对40转账的情况下,消耗的gas大致在130万上下,如果ETH一个区块的gas上限大致为800万,那么,1次完成1对240转账就快将区块的gas上限给占满了。假如出现单次转账的收款对象数量太多的情况,也会出现超出区块gas上限而致使双方交易无法完成的结果。基于以上的问题,在遇到优盾钱包这个开放平台后,我果断放弃了之前的研究,通过API直接对接交易所,免节点同步,便捷又省心。
相关文章:
1、BTC bitcoin-cli转账及交易的API使用教程
2、区块链交易所钱包添币指南!
3、答疑笔记 | 这10类区块链钱包问题,业内人士最关注
4、区块链交易所钱包实现原理揭秘!