# Airdrop

By [startha](https://paragraph.com/@starha) · 2023-10-30

---

[空投Airdrop](https://github.com/starthapro/starha_solidity/blob/main/32_Airdrop/readme.md#%E7%A9%BA%E6%8A%95airdrop)
-------------------------------------------------------------------------------------------------------------------

空投是币圈中一种营销手段，项目方将代币免费发放给特定用户群体。为了拿到空投资格，用户通常需要完成一些简单的任务，如测试产品、分享新闻、介绍朋友等。项目方通过空投可以获得种子用户，而用户可以获得一笔财富，两全其美。

因为每次接收空投的用户很多，项目方不可能一笔一笔的转账。利用只能合约批量发放`ERC20`代币，可以显著提高空投效率。

### [空投代币合约](https://github.com/starthapro/starha_solidity/blob/main/32_Airdrop/readme.md#%E7%A9%BA%E6%8A%95%E4%BB%A3%E5%B8%81%E5%90%88%E7%BA%A6)

`Airdrop`空投合约逻辑非常简单：利用循环，一笔交易将`ERC20`代币发送给多个地址。合约中包含两个函数：

*   `getSum()`函数：返回`uint`数组的和。
    

        //数组求和函数
        function getSum(uint256[] calldata _arr) public pure returns(uint sum) {
            for(uint i = 0; i< _arr.length; i++) {
                sum = sum + _arr[i];
            }
        }
    

*   `multiTransferToken()`函数：发送`ERC20`代币空投，包含3个参数：
    
    *   `_token`：代币合约地址（`address`类型）
        
    *   `_addresses`：接收空投的用户地址数组（`address[]`类型）
        
    *   `_amount`：空投数量数组，对应`_addresses`里每个地址的数量（`uint[]`类型）
        

该函数有两个检查：第一个`require`检查了`_addresses`和`_amounts`两个数组长度是否相等；第二个`require`检查了空投合约的授权额度大于要空投的代币数量总和。

        // @notice 向多个地址转账ERC20代币，使用前需要先授权
        // @param _token 转账的ERC20代币地址
        // @param _addresses 空投地址数组
        // @param _amounts 代币数量数组（每个地址的空投数量）
        function multiTransferToken(address _token, address[] calldata _addresses, uint256[] calldata _amounts) external {
            require(_addresses.length == _amounts.length, "Lengths of Addresses and Amounts NOT EQUAL");
    
            IERC20 token = IERC20(_token); //声明IERC20合约变量
            uint _amountSum = getSum(_amounts); //计算空投代币总量
    
            //检查：授权代币数量 > 空投代币总量
            require(token.allowance(msg.sender, address(this)) > _amountSum, "Need Approve ERC20 token");
            for(uint256 i = 0; i < _addresses.length; i++) {
                token.transferFrom(msg.sender, _addresses[i],_amounts[i]);
            }
        }
    

*   `multiTransferEth()`函数：发送`ETH`空投，包含两个参数：
    
    *   `_addresses`：接收空投的用户地址数组（`address[]`类型）
        
    *   `_amount`：空投数量数组，对应`_addresses`里每个地址的数量（`uint[]`类型）
        

        //向多个地址转账eth
        function multiTransferETH(address payable[] calldata _addresses, uint256[] calldata _amounts) public payable {
            require(_addresses.length == _amounts.length, "Lengths of Addresses and Amounts NOT EQUAL");
    
            uint _amountSum = getSum(_amounts);
            //检查转入ETH等于空投总量
            require(msg.value == _amountSum, "Transfer amount error");
    
            //for循环，利用transfer函数发送ETH
            for(uint256 i = 0; i < _addresses.length; i++){
                // 注释代码有Dos攻击风险, 并且transfer 也是不推荐写法
                // Dos攻击 具体参考 https://github.com/AmazingAng/WTF-Solidity/blob/main/S09_DoS/readme.md
                // _addresses[i].transfer(_amounts[i]);
                (bool success, ) = _addresses[i].call{value: _amounts[i]}("");
                if(!success) {
                    failTransferList[_addresses[i]] = _amounts[i];
                }
            }
        }
    

### [空投实践](https://github.com/starthapro/starha_solidity/blob/main/32_Airdrop/readme.md#%E7%A9%BA%E6%8A%95%E5%AE%9E%E8%B7%B5)

1\. 部署`ERC20`代币合约，并给自己`mint`10000单位代币

![](https://storage.googleapis.com/papyrus_images/ab016b5573af085d4caf0875ae2ad425068b7948c5caa17fe1194812331cd887.png)

![](https://storage.googleapis.com/papyrus_images/d7b2885a2051bab889c16f1861d8888e946465578b2e21a925d8e0811bb0bb20.png)

2\. 部署`Airdrop`空投合约。

![](https://storage.googleapis.com/papyrus_images/79b073bcbba5aa623c881a65542e346cd688c37122ac61add821978552fc1535.png)

3\. 利用`ERC20`代币合约中的`approve()`函数，给`Airdrop`空投合约授权`10000`单位代币。

![](https://storage.googleapis.com/papyrus_images/864412c1de0c7e89977e899553b654109fc4e32a2a6ab7d24d825885058600c2.png)

4\. 执行`Airdrop`合约的`multiTransferToken()`函数进行空投，`_token`填`ERC20`代币地址，`_addresses`和`_amounts`按照以下填写

    // _addresses填写
    ["0xAb8483F64d9C6d1EcF9b849Ae677dD3315835cb2","0x4B20993Bc481177ec7E8f571ceCaE8A9e22C02db"]
    
    // _amounts填写
    [100, 200]
    

![](https://storage.googleapis.com/papyrus_images/e5a907427c137a0960348d56a729db8905132877ced31223903083895aca3414.png)

5\. 利用`ERC20`合约的`balanceOf()`函数查询上面用户地址的代币余额，成功变为100和200，空投成功！

![](https://storage.googleapis.com/papyrus_images/167472a6c8e625c1e450d5515a0f1374e14d9f0ec25b6580b7a8cb4e95d5d972.png)

![](https://storage.googleapis.com/papyrus_images/2859be008ba75cbc6010b95569eb33edea986b6c022cf3bf88f7abf8e6eb9f57.png)

---

*Originally published on [startha](https://paragraph.com/@starha/airdrop)*
