上回的空投合约非常的简单就一个负责转账的函数:
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.最后发起空投,查看一下他们是否收到了奖励。
下面是他们账户的截图:
最后
现在这个合约与之前相比,有了很大的改进,让大家更加方便地加入我们的活动。但是合约目前都只是考虑功能方面,在安全性方面还有不足,所以我们还需要继续学习新知识来更好地完善它。