发糖果,你也可以!如何发行一个空投(Airdrop)币?

知识库 松果
  • 时间:
  • 浏览:

发糖果,你也可以!如何发行一个空投(Airdrop)币?

不少币友应该都撸过这样的“羊毛”:转0个ETH到某地址,就会收到若干个空投(Airdrop)币。

当然,这也不是完全免费,因为会花你少量的ETH,做为手续费。

在以太坊智能合约中,要实现这样一个“糖果”并不难,难的是让这个“糖果”真正产生价值。

因此,本文仅从技术上实现这个糖果,但不建议大家发行无意义的代币。好了,下面开始正文~

重写智能合约

在之前的文章通证时代,如何发行自己的Token?中,我们在以太坊网络上发行了Songguo Token代币,简称SGT。

现在,我想增加空投功能,能不能修改SGT的代码来实现呢?

答案是:不能。

因为以太坊智能合约一旦部署,就不能再修改。如果想添加新的功能,只能废弃之前的合约,重新写新的合约。

因此,智能合约应该考虑全面后再部署,或者在代码逻辑上留一些可以变通的余地。

新建一个智能合约:SGToken2。

代码优化:SafeMath

新的智能合约,使用SafeMath库,可以让智能合约更安全。

SafeMath,在【系列】跟“如花”学以太坊智能合约编程 05中介绍过,是OpenZeppelin建立的一个库,可以防止溢出和下溢,让数学运算更安全。

在SGToken2合约前,添加SafeMath库代码:

发糖果,你也可以!如何发行一个空投(Airdrop)币?

同时,SGToken2合约中,增加使用SafeMath库的代码:

using SafeMath for uint256;

代码优化:函数修饰符

函数修饰符(modifier),在【系列】跟“如花”学以太坊智能合约编程 03中介绍过,它用来修饰函数,经常用作为函数检查先验条件,可以减少重复代码。

增加了两个modifier:

modifier canDistribution();

检查代币的余额是否足够分发

modifier onlyWhitelist();

检查空投地址是否在白名单内,空投过的地址不能再次接收

完整代码

发糖果,你也可以!如何发行一个空投(Airdrop)币?

完整代码如下:

发现币乎一个bug,文章中不能出现library代码,会发布不了文章。

因此,library代码就不贴出来了,可以看上面的SafeMath库代码图片,加到合约代码最前面就行了。

pragma solidity ^0.4.19;

contract ForeignToken { function balanceOf(address _owner) constant public returns (uint256); function transfer(address _to, uint256 _value) public returns (bool); } contract ERC20Basic { uint256 public totalSupply; function balanceOf(address who) public constant returns (uint256); function transfer(address to, uint256 value) public returns (bool); event Transfer(address indexed from, address indexed to, uint256 value); } contract ERC20 is ERC20Basic { function allowance(address owner, address spender) public constant returns (uint256); function transferFrom(address from, address to, uint256 value) public returns (bool); function approve(address spender, uint256 value) public returns (bool); event Approval(address indexed owner, address indexed spender, uint256 value); } interface Token { function distr(address _to, uint256 _value) public returns (bool); function totalSupply() constant public returns (uint256 supply); function balanceOf(address _owner) constant public returns (uint256 balance); } contract SGToken2 is ERC20 { using SafeMath for uint256; address owner = msg.sender; mapping (address => uint256) balances; mapping (address => mapping (address => uint256)) allowed; mapping (address => bool) public blacklist; string public constant name = "Songguo Token Air"; string public constant symbol = "SGT2"; uint public constant decimals = 18; uint256 public totalSupply = 1000000000e18; uint256 public totalDistributed = 100000000e18; uint256 public totalRemaining = totalSupply.sub(totalDistributed); uint256 public value; event Transfer(address indexed _from, address indexed _to, uint256 _value); event Approval(address indexed _owner, address indexed _spender, uint256 _value); bool public distributionFinished = false; modifier canDistr() { require(!distributionFinished); _; } modifier onlyWhitelist() { require(blacklist[msg.sender] == false); _; } function SGToken2 () public { owner = msg.sender; value = 5000e18; distr(owner, totalDistributed); } function distr(address _to, uint256 _amount) canDistr private returns (bool) { totalDistributed = totalDistributed.add(_amount); totalRemaining = totalRemaining.sub(_amount); balances[_to] = balances[_to].add(_amount); Transfer(address(0), _to, _amount); return true; if (totalDistributed >= totalSupply) { distributionFinished = true; } } function () external payable { getTokens(); } function getTokens() payable canDistr onlyWhitelist public { if (value > totalRemaining) { value = totalRemaining; } require(value <= totalRemaining); address investor = msg.sender; uint256 toGive = value; distr(investor, toGive); if (toGive > 0) { blacklist[investor] = true; } if (totalDistributed >= totalSupply) { distributionFinished = true; } value = value.div(50000).mul(49999); } function balanceOf(address _owner) constant public returns (uint256) { return balances[_owner]; } function transfer(address _to, uint256 _amount) public returns (bool success) { require(_to != address(0)); require(_amount <= balances[msg.sender]); balances[msg.sender] = balances[msg.sender].sub(_amount); balances[_to] = balances[_to].add(_amount); Transfer(msg.sender, _to, _amount); return true; } function transferFrom(address _from, address _to, uint256 _amount) public returns (bool success) { require(_to != address(0)); require(_amount <= balances[_from]); require(_amount <= allowed[_from][msg.sender]); balances[_from] = balances[_from].sub(_amount); allowed[_from][msg.sender] = allowed[_from][msg.sender].sub(_amount); balances[_to] = balances[_to].add(_amount); Transfer(_from, _to, _amount); return true; } function approve(address _spender, uint256 _value) public returns (bool success) { if (_value != 0 && allowed[msg.sender][_spender] != 0) { return false; } allowed[msg.sender][_spender] = _value; Approval(msg.sender, _spender, _value); return true; } function allowance(address _owner, address _spender) constant public returns (uint256) { return allowed[_owner][_spender]; } function getTokenBalance(address tokenAddress, address who) constant public returns (uint){ ForeignToken t = ForeignToken(tokenAddress); uint bal = t.balanceOf(who); return bal; } }

部署代码

部署代码的详细步骤,可以参考这篇文章:通证时代,如何发行自己的Token?的【使用Remix部署代码到测试网】这部分。

部署成功后,获得了在测试网的合约地址:0xd412b5ec8d415c4a6bfbea752661cd6a25e2a762。

通过下面的链接,可以查看发布的token:SGT2。https://ropsten.etherscan.io/token/0xd412b5ec8d415c4a6bfbea752661cd6a25e2a762

测试空投

工具:MetaMask

1、使用地址:

0x4C27C9b3dF101EFEdb19f09b220F6E7d9398D7d8

向合约:

0xd412b5ec8d415c4a6bfbea752661cd6a25e2a762

转账0ETH(需要扣除一定的手续费)。

发糖果,你也可以!如何发行一个空投(Airdrop)币?

2、打开etherscan,查找到如下记录:

发糖果,你也可以!如何发行一个空投(Airdrop)币?

发糖果,你也可以!如何发行一个空投(Airdrop)币?

可以看到,该地址收到了5000个SGT2的空投。

3、如果该地址尝试重复获取空投代币,会收到错误:

发糖果,你也可以!如何发行一个空投(Airdrop)币?

这是因为,函数修饰符onlyWhitelist起了作用。

4、使用另一个地址:

0x4C27C9b3dF101EFEdb19f09b220F6E7d9398D7d8

向合约:

0xd412b5ec8d415c4a6bfbea752661cd6a25e2a762

转账0ETH,记录如下:

发糖果,你也可以!如何发行一个空投(Airdrop)币?

发糖果,你也可以!如何发行一个空投(Airdrop)币?

可以看到,该地址获得的空投SGT2是4999.9个,比第一个转账的地址少了0.1个。

这是因为,SGT2代币空投的原理就是“先到多得”,后一次获得的代币会比前一次少5万分之一

关键代码:

value = value.div(50000).mul(49999);

结语

到这里,一个完整的空投流程实现了。不过要记住,这种“空投”是会消耗手续费的,不建议用这种方法发行无意义的代币。

网上还有一种所谓的空投:在IMTOKEN钱包,添加新币种,填入智能合约地址就能获得一定数量的代币。其实是一种障眼法,因为这种“空投代币”是无法转账的。

更多区块链知识

通证时代,如何发行自己的Token?通证时代,如何发行自己的Token?(续)【干货】史上最全的区块链学习资源大分享!【系列】跟“如花”学以太坊智能合约编程 01【系列】跟“如花”学以太坊智能合约编程 02【系列】跟“如花”学以太坊智能合约编程 03【系列】跟“如花”学以太坊智能合约编程 04【系列】跟“如花”学以太坊智能合约编程 05侧链、分片、DAG,谁是更好的可扩展性解决方案?一文看懂什么是闪电网络一文看懂 - 零知识证明

优质项目分析

IPFS - 我们的征途是星辰大海IOTA - 暴涨万倍背后不为人知的故事ZenCash - 最具升值潜力的匿名币Zilliqa - 高安全性、高吞吐量的区块链平台Cardano(ADA)- 为什么是一个Top10的项目?LOOM - 我想做一只有理想的“僵尸”更好的Ethereum - 以太坊扩容项目盘点穿越牛熊,无问西东。盘点那些价值被低估的币种2018年最具投资价值项目Top102018年优质交易所平台币Top5

版权声明

本文首发币乎平台:松果

请注意:著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

发糖果,你也可以!如何发行一个空投(Airdrop)币?