# 实战案例三：ICO 初始代币销售与空投

By [icepy](https://paragraph.com/@icepy) · 2022-03-20

---

最近 APE 空投这么火，是时候说到如何为我们之前做的 UseWeb3NFT 发行代币，在进入编码之前，我们先梳理一下具体的需求：

*   假设令牌的最大数量为 10000 个
    
*   每一个 UseWeb3NFT 持有者可以免费领取 10个
    
*   ICO 时每一个令牌的初始价格为 0.0001 eth
    

ERC-20

*   [https://docs.openzeppelin.com/contracts/2.x/api/token/erc20](https://docs.openzeppelin.com/contracts/2.x/api/token/erc20)
    

由于空投部分需要依赖 UseWeb3NFT，所以我们需要写一个接口，使用外部调用的方式获取一些数据

    interface IUseWeb3NFT {
      function balanceOf(address owner) external view returns (uint256 balance);
      function ownerOf(uint256 tokenId) external view returns (address ownerAddress);
    }
    

首先，我们需要去定义价格

    uint256 public constant tokenPrice = 0.0001 ether;
    uint256 public constant tokenMax = 10000 * 10**18;
    uint256 public constant nftClaimTokenValue = 10 * 10**18;
    

初始代币销售的价格为 0.0001 eth，代币总数为 10000 个，一个 NFT 可以获取空投的数量为 10 个

接下来我们需要一个 map 去存储已经 Claim 的 tokenId，你总不希望每一个 tokenId 都能重复获取空投吧？

    mapping (uint256 => bool) claimed;
    

对于销售部分：

    function mint(uint256 amount) public payable{
      uint256 requireAmount = tokenPrice * amount;
      require(msg.value >= requireAmount, "sent is incorrect");
      uint256 amountAll = amount * 10**18;
      require((totalSupply() + amountAll) <= tokenMax, "! max");
      _mint(msg.sender, amountAll);
    }
    

对于空投部分：

    function claim(uint256[] calldata tokenIds) external{
      require(tokenIds.length > 0, "Shortage TokenId");
      address sender = msg.sender;
      uint256 balance = useweb3NFT.balanceOf(sender);
      require(balance > 0, "Not Balance");
      uint256 amount = 0;
      for (uint i = 0; i < tokenIds.length; i++) {
        address ownerAddress = useweb3NFT.ownerOf(tokenIds[i]);
        if (sender == ownerAddress && !claimed[tokenIds[i]]) {
          amount++;
          claimed[tokenIds[i]] = true;
        }
      }
      require(amount > 0, "claimed all the tokens");
      _mint(sender, amount * nftClaimTokenValue);
    }
    

提款方法：

    function withdraw() public onlyOwner {
      address _owner = owner();
      uint256 amount = address(this).balance;
      (bool sendStatus, ) = _owner.call{value: amount}("");
      require(sendStatus, "Failed send");
    }

---

*Originally published on [icepy](https://paragraph.com/@icepy/ico)*
