solidity实现智能合约教程(3)-空投合约

文章目录

  • 1 介绍
  • 2 主要功能
  • 3 代码示例
  • 4 部署测试

猛戳订阅学习专栏 solidity系列合约源码+解析

solidity实现智能合约教程(3)-空投合约_第1张图片

1 介绍

空投就是一种营销策略,通过空投活动将某种数字货币或代币分发给用户,通常需要用户完成一项简单的任务,如分享新闻、介绍朋友或拥有某种数字货币,目前也被广泛应用于宣传新币种,在数字货币市场中反响不错。本文将和大家一起编写我们常见的糖果空投合约。

“发送 0 个 ETH 到某个地址,立马获得 5000 枚 Token,每个地址只能获取一次”,相信大家对于此类糖果空投的信息都已经遇见过很多次了,也有很多朋友趁此机会薅了很多羊毛。身为开发人员,我们不应只是简单的薅羊毛,更应该深入地去研究此类糖果空投的实现原理。

最简单的实现方式是通过人工手动来处理每笔空投,但耗时耗力不够智能还极易出错。若是通过智能合约来实现,不仅省时省力,还不易出错。

2 主要功能

本篇文章空投合约实现主要功能:

  1. 通过合约给单个地址转ETH
  2. 通过合约一次性给多个地址转ETH(平均分配金额)
  3. 通过合约一次性给多个地址转ETH(指定金额)
  4. 通过合约一次性给多个地址转移ERC20代币(固定个数)
  5. 通过合约一次性给多个地址转移ERC20代币(指定个数)
  6. 通过合约给单个地址转移ERC721 NFT(指定NFT)
  7. 通过合约给单个地址转移单个ERC1155代币
  8. 通过合约给单个地址转移不同数量的ERC1155代币

我们先来看一下标准的 ERC20 标准的接口:

3 代码示例

本篇文章使用到的智能合约开发库:
openzeppelin
有兴趣的同学可以去看一下他们的源码。

下面让我们来给出完整的空投合约代码:

合约代码:

// SPDX-License-Identifier: MIT;
pragma solidity ^0.8;

import "@openzeppelin/contracts/token/ERC721/IERC721.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/token/ERC1155/IERC1155.sol";

contract kongTou {

 
    address owner;


    modifier onlyOwner() {
        require(msg.sender == owner, "only owner can call this");
        _;
    }

    modifier notAddress(address _useAdd){
        require(_useAdd != address(0), "address is error");
        _;
    }

    event Received(address, uint);

    constructor() payable{
        owner = msg.sender;
    }

    receive() external payable {
        emit Received(msg.sender, msg.value);
    }

    function pay() public payable{

    }

    function transferEthsAvg(address[] memory _tos) 
        payable 
        public 
        onlyOwner
        returns (bool) {

        require(_tos.length > 0);

        uint oneValue = address(this).balance/_tos.length;

        for(uint i=0; i<_tos.length; i++){
            require(_tos[i] != address(0));
            payable(_tos[i]).transfer(oneValue);
        }

        return true;

    }

    function transferEths(address[] memory _tos,uint256[] memory _values) 
        payable 
        public 
        onlyOwner
        returns (bool) {

        require(_tos.length > 0);
        require(_tos.length == _values.length);

        for(uint32 i=0;i<_tos.length;i++){
            require(_tos[i] != address(0));
            require(_values[i] > 0);
            payable(_tos[i]).transfer(_values[i]);
        }

        return true;
    }

    function transferEth(address _to) 
        payable 
        public 
        onlyOwner
        returns (bool){

        require(_to != address(0));
        require(msg.value > 0);

        payable(_to).transfer(msg.value);

        return true;

    }

    function checkBalance() 
        public 
        view 
        returns (uint) {

        return address(this).balance;
    }



    function destroy() 
        public
        onlyOwner
         {

        selfdestruct(payable(msg.sender));

    }

    function transferTokensAvg(address from,address _constractAdd,address[] memory _tos,uint _v)
        public 
        onlyOwner
        notAddress(from)
        notAddress(_constractAdd)
        returns (bool){

        require(_tos.length > 0);
        require(_v > 0);

        IERC20 _token = IERC20(_constractAdd);
        

        //要调用的方法id进行编码
        // bytes4 methodId = bytes4(keccak256("transferFrom(address,address,uint256)"));

        for(uint i=0;i<_tos.length;i++){
            require(_tos[i] != address(0));

            require(_token.transferFrom(from,_tos[i],_v));
            // _constractAdd.call(abi.encodeWithSignature("transferFrom(address,address,uint256)",from,_tos[i],_v));
            // _constractAdd.call(methodId,from,_tos[i],_v);
        }
        return true;

    }


    function transferTokens(address from,address _constractAdd, address[] memory _tos,uint[] memory _values)
        public 
        onlyOwner
        notAddress(from)
        returns (bool){

        require(_tos.length > 0);
        require(_values.length > 0);
        require(_values.length == _tos.length);

        bool status;
        bytes memory msgs;

        //要调用的方法id进行编码
        // bytes4 methodId = bytes4(keccak256("transferFrom(address,address,uint256)"));

        for(uint i=0;i<_tos.length;i++){
            require(_tos[i] != address(0));
            require(_values[i] > 0);


            (status,msgs) = _constractAdd.call(abi.encodeWithSignature("transferFrom(address,address,uint256)",from,_tos[i],_values[i]));
            require(status == true);

            // require(_constractAdd.call(methodId,from,_tos[i],_values[i]));
            
        }

        return true;

    }

    function transferTokenOne(address _from,address _constractAdd,address _to,uint _tokenId)
        public
        notAddress(_from)
        notAddress(_constractAdd)
        notAddress(_to)
        onlyOwner
        returns(bool){
            IERC721 _token = IERC721(_constractAdd);
            _token.safeTransferFrom(_from,_to,_tokenId);
            return true;
        }

    function transferToken1155(address _from,address _contractAdd,address _to,uint _tokenId,uint _num)
        public
        notAddress(_from)
        notAddress(_contractAdd)
        notAddress(_to)
        returns(bool){
            IERC1155 _token = IERC1155(_contractAdd);
            _token.safeTransferFrom(_from,_to,_tokenId,_num,"");
            return true;
        }

    function transferTokenBatch1155(address _from,address _contractAdd,address _to,uint[] memory _tokenIds,uint[] memory _nums)
        public
        notAddress(_from)
        notAddress(_contractAdd)
        notAddress(_to)
        returns(bool){
            IERC1155 _token = IERC1155(_contractAdd);
            _token.safeBatchTransferFrom(_from,_to,_tokenIds,_nums,"");
            return true;
        }

}

下面解释一下上面用到的合约和方法:

  • @openzeppelin/contracts/token/ERC721/IERC721.sol 该合约实现了标准的IERC721接口中的方法
  • @openzeppelin/contracts/token/ERC20/IERC20.sol 该合约实现了标准的IERC20接口中的方法
  • @openzeppelin/contracts/token/ERC1155/IERC1155.sol 该合约实现了标准的IERC1155接口中的方法
  • modifier onlyOwner() 该修饰器为修饰某个方法权限为只能合约部署者调用
  • modifier notAddress(address _useAdd) 改修饰器为修饰判断某个address类型的值不为0地址
  • event Received() 该event事件为合约收到转账时候触发
  • constructor() //合约的构造方法,在合约创建时候存储合约创建者的地址,添加payable,支持在创建合约的时候,value往合约里面转eth
  • receive() 当合约收到转账时候该方法会被调用,方法内实现了去触发Received event事件
  • pay() 该方法定义了payable,代表后面可以通过该方法往合约里面转移ETH
  • transferEthsAvg(address[] memory _tos) //批量转移ETH,平分发给_tos数组里面的地址,
  • transferEths(address[] memory _tos,uint256[] memory _values) //给每个地址转不同数量的ETH,其中_tos和_values数组里面的地址和数量要一一对应
  • transferEth(address _to) //通过合约直接给_to地址转移ETH
  • checkBalance() //检查合约账户剩余的可用ETH数量
  • destroy() 销毁合约,合约被销毁后,合约中剩余的ETH将会被转移到合约铸造者地址中,且合约后面将不再可用
  • transferTokensAvg(address from,address _constractAdd,address[] memory _tos,uint _v) //批量给每一个地址转移ERC20 Token,每个地址转一样数量, 其中 from为要转出token的地址,_constractAdd为要转移的ERC20的合约地址,_tos为要批量转给的用户数组,_v为给每个地址转移的ERC20的数量
  • transferTokens(address from,address _constractAdd, address[] memory _tos,uint[] memory _values) //批量给每一个地址转移ERC20 Token,每个地址转不一样的数量,其中 from为要转出token的地址,_constractAdd为要转移的ERC20的合约地址,_tos为要批量转给的用户数组,_values为给每个地址转移的ERC20的数量,_tos和_values要一一对应
  • transferTokenOne(address _from,address _constractAdd,address _to,uint _tokenId) //转移单个ERC721的NFT,其中 from为要转出token的地址,_constractAdd为要转移的ERC721的合约地址,_to为要转到的地址,_tokenId为要转移的ERC721的token ID
  • transferToken1155(address _from,address _contractAdd,address _to,uint _tokenId,uint _num) //转移单个ERC1155的代币,其中 from为要转出token的地址,_constractAdd为要转移的ERC1155的合约地址,_to为要转到的地址,_tokenId为要转移的ERC721的token ID,_num为要转移的该token ID的数量
  • transferTokenBatch1155(address _from,address _contractAdd,address _to,uint[] memory _tokenIds,uint[] memory _nums) //给某个address转移多个ERC1155的代币,其中 from为要转出token的地址,_constractAdd为要转移的ERC1155的合约地址,_to为要转到的地址,_tokenIds为要转移的ERC721的token ID组成的数组,_nums为要转移的token ID的数量组成的数组

注意:在操作转移相应的token之前,都要先用相应的_from地址调用token合约的授权方法,允许该空投合约转移_from地址一定数量的token

4 部署测试

solidity实现智能合约教程(3)-空投合约_第2张图片

我们选择要部署的合约为 kongtou ,点击 Deploy 进行部署,可以看到部署后的合约地址和相应的合约方法

solidity实现智能合约教程(3)-空投合约_第3张图片

为了测试我们的空投合约的功能,再部署一下前面学到的ERC20合约,部署时候要换一个地址,并给该地址铸造了1000个代币。

solidity实现智能合约教程(3)-空投合约_第4张图片
下面给空投合约授权转移的token数量为100个,为了下一步的批量转移token。并且查询验证一下。

solidity实现智能合约教程(3)-空投合约_第5张图片
接下来我们给2个地址转移了ERC20 token,每个地址转移的数量为25个,这一步调用合约时候的地址为 部署空投合约的地址

solidity实现智能合约教程(3)-空投合约_第6张图片
最后一步我们用之前接收ERC20代币的地址数组中的一个查询一下他的ERC20的余额,结果为25个,验证了我们的此次批量转移token是成功的。

好了,批量转移token的空投合约到这里就结束了,学会了这个合约就可以举一反三做出来很多其他类似的空投合约!

你可能感兴趣的:(智能合约,区块链,以太坊)