上回的空投合约十分的简略就一个负责转账的函数:
Airdrop.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
import "./IERC20.sol"; //import IERC20
contract Airdrop {
function multiTransferToken(
address _token,
address[] calldata _addresses) external {IERC20 token = IERC20(_token);
uint _amountSum = _addresses.length * 100;
require(token.allowance(msg.sender, address(this)) > _amountSum, "Need Approve ERC20 token");
for (uint256 i; i < _addresses.length; i++) {token.transferFrom(msg.sender, _addresses[i], 100)
}
}
}
当初,咱们来欠缺一下它,给它降级一下。
降级合约
首先,咱们来剖析一下须要欠缺的点:
1. 发动空投得本人输出账户地址数组,如果数量多了,会很麻烦;
解决思路:既然是空投合约,那么就应该是给被动参加咱们流动的账户都投递空投,咱们须要设置一个 join 函数让大家被动退出流动,流动处分。
2. 空投的代币数量固定,不够不便;
解决思路:给每个参加空投的账户设置一个空投数量,用一个数组存储它们,还得能由合约拥有者进行设置,这样就更灵便了。
那么首先,咱们要定义一个数组来存储参加空投的账户地址和它们对应的空投数量,在这里 mapping 就是很好的抉择了:
mapping(address => uint) private _addresses;
之后,咱们写一个加入流动的函数:
function join() public {payable(msg.sender).transfer(0);
_add(msg.sender);
}
function _add(address _address) private {require(_addresses[_address] == 0,"This address has already participated in the activity!");
_addresses[_address] = 100;
_addressArr.push(_address);
_token.approve(_address,_addresses[_address]);
}
接下来,咱们写一个设置空投数量的函数:
function setAirdropNumber(address _address, unit num) public {require(msg.sender == owner,"you are not owner!")
_addresses[_address] = num;
}
发动空投的函数也须要批改一番:
function multiTransferToken() external {uint _amountSum = _getSum(_addressArr);
require(_token.balanceOf(address(this)) >= _amountSum, "Need enough ERC20 token");
for (uint i; i < _addressArr.length; i++) {_token.transfer(_addressArr[i], _addresses[_addressArr[i]]);
}
}
function _getSum(address[] memory _arr) private view returns(uint sum){
sum = 0;
for(uint i = 0; i < _arr.length; i++){sum = sum + _addresses[_arr[i]];
}
}
依据以上的代码和需要,咱们对代码进一步进行欠缺,最终的代码就呈现了:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
import "./IERC20.sol"; //import IERC20
/// @notice 向多个地址转账 ERC20 代币
contract Airdrop {
address private _owner;
IERC20 private _token;
mapping(address => uint) private _addresses;
address[] private _addressArr;
constructor(address tokenAddress) {
_owner = msg.sender;
_token = IERC20(tokenAddress);
}
function join() public {payable(msg.sender).transfer(0);
_add(msg.sender);
}
function _add(address _address) private {require(_addresses[_address] == 0,"This address has already participated in the activity!");
_addresses[_address] = 100 * (10 ** 18);
_addressArr.push(_address);
_token.approve(_address,_addresses[_address]);
}
function setAirdropNumber(address _address, uint num) public {require(_owner == msg.sender, "you are not owner!");
_addresses[_address] = num;
_token.approve(_address,_addresses[_address]);
}
function multiTransferToken() external {uint _amountSum = _getSum(_addressArr);
require(_token.balanceOf(address(this)) >= _amountSum, "Need enough ERC20 token");
for (uint i; i < _addressArr.length; i++) {_token.transfer(_addressArr[i], _addresses[_addressArr[i]]);
}
}
function _getSum(address[] memory _arr) private view returns(uint sum){
sum = 0;
for(uint i = 0; i < _arr.length; i++){sum = sum + _addresses[_arr[i]];
}
}
}
当初,将新合约部署上链,测试一下吧。
测试合约
1. 将之前的代币设置为合约的默认处分代币;
2. 在 CHAINPIP 社区中先将退出流动的性能凋谢进去,这样所有想退出的敌人都能够退出流动;
3. 当初咱们应用俩个测试账户来退出流动:
地址 1:0x754EcB8939e806b365f59aeF9Eadf0cd12b84831
地址 2:0x0A67e0A87b9E436808253E3a6EdA2ce333996ccB
4. 之后咱们给其中一个账户批改一下空投的数量,将数量批改为 300:
地址:0x754EcB8939e806b365f59aeF9Eadf0cd12b84831
5. 最初发动空投,查看一下他们是否收到了处分。
上面是他们账户的截图:
最初
当初这个合约与之前相比,有了很大的改良,让大家更加不便地退出咱们的流动。然而合约目前都只是思考性能方面,在安全性方面还有有余,所以咱们还须要持续学习新常识来更好地欠缺它。