# 智能合约示例:给跑步群发 Token,跑步赚 Token **Published by:** [0xdoux.eth](https://paragraph.com/@0xdoux/) **Published on:** 2022-03-30 **URL:** https://paragraph.com/@0xdoux/token-token ## Content 在上文里我们介绍了如何将跑步数据上传到智能合约里,在本文里,将介绍如何给跑步群发行 Token。本文仅为演示如何使用智能合约发 Token,仅作为技术交流。 Token 介绍 在区块链中,Token 也叫做代币,例如 ETH,它可以作为货币、积分、资产等的使用。在区块链世界里,token 是非常重要的基础设施,大部分的项目都会设计 token economy。得益于以太坊等平台的技术能力,项目发行 token 在技术层面是比较简单的,难的在于如何设计一个优秀的 token economy。 在以太坊上,ERC20 是 token 的标准,在标准中定义了一系列的接口规范,项目方只需要在合约里实现了这些接口规范,这个合约就是 token。这个接口要求如下: function name() public view returns (string) function symbol() public view returns (string) function decimals() public view returns (uint8) function totalSupply() public view returns (uint256) function balanceOf(address _owner) public view returns (uint256 balance) function transfer(address _to, uint256 _value) public returns (bool success) function transferFrom(address _from, address _to, uint256 _value) public returns (bool success) function approve(address _spender, uint256 _value) public returns (bool success) function allowance(address _owner, address _spender) public view returns (uint256 remaining) event Transfer(address indexed _from, address indexed _to, uint256 _value) event Approval(address indexed _owner, address indexed _spender, uint256 _value) 简单来说,一个 token 要有一个名字、符号、当前供给量,具有获取余额、转账、代持等操作,同时在执行特定操作的时候抛出日志信息即可。符号用来标识一个具体的 token,如 ETH、APE 等。 需求设计 因此,要发行 token,只需要依次实现上述的接口要求即可。在本文的示例里,我们暂不实现 allownace、approve 的接口。 在设计上,我们满足如下需求: token 命名为 RNC,在上线时,管理员获得 100000 RNC 初始持仓 用户上传跑步数据,可以获得对应里程的 RNC 代币,一米对应一个 RNC,且最低里程为 2 公里 用户可以查询自己的 token 额度,可以转账 目前仅做了上述的设计,后续还可以加入更多的设计,比如质押 RNC 参加跑步挑战,完不成的挑战的 RNC 一部分做奖励、一部分做销毁等。感兴趣的读者可以留言提出需求,我们在后续的文章里可以来实现。 合约实现 首先,在构造器里,确定 token 的一些属性 string private _name; string private _symbol; uint8 private _decimal; uint256 private _totalSupply; address owner; mapping(address => uint256) balances; constructor() { _name = "RunningClub"; _symbol = "RNC"; _decimal = 3; owner = msg.sender; balances[owner] = _totalSupply = 100000; } 通过 balances 来记录每个钱包的 token 数,通过 _totalSupply 来记录当前合约的总供给数 接下来,可以实现接口规范中的一些属性接口 function name() public view returns (string memory) { return _name; } function symbol() public view returns (string memory) { return _symbol; } function decimals() public view returns (uint8) { return _decimal; } function totalSupply() public view returns (uint256) { return _totalSupply; } 实现查询账户金额的接口,通过对合约数据的读取即可完成,no big deal function balanceOf(address _owner) public view returns (uint256) { return balances[_owner]; } function balanceOfMe() public view returns (uint256) { return balances[msg.sender]; } 还有转账的相关操作,通过对不同账户的增加和减少余额即可实现,需要注意的是,在转账钱要验证下账户的余额和要转出的余额之间的大小,不能出现余额不够的情况 event Transfer(address indexed _from, address indexed _to, uint256 _value); function transfer(address _to, uint256 _value) public returns (bool) { require(balances[owner] > _value, "amount is not enough to transfer"); require(owner != msg.sender, "cannot transfer to self"); balances[owner] -= _value; balances[_to] += _value; emit Transfer(owner, _to, _value); return true; } function transferFrom(address _from, address _to, uint256 _value) public returns (bool) { require(balances[_from] > _value, "amount is not enough to transfer"); require(_from != _to, "cannot transfer to self"); balances[_from] -= _value; balances[_to] += _value; emit Transfer(_from, _to, _value); return true; } 最后,就是实现上传跑步数据就能获得 RNC 奖励的需求 mapping(address => uint[]) runningRecords; function _mint(address _user, uint _amount) private { balances[_user] += _amount; _totalSupply += _amount; } function checkIn(uint _miles) public { require(_miles >= MIN_MILES, "min miles should be 2000 miles"); runningRecords[msg.sender].push(_miles); _mint(msg.sender, _miles); } 只要跑步的里程数达到合约的要求,就给该账户增加对应额度的 RNC,同时更新总供给即可。 总结 上述示例中,还没有去实现 ERC20 所要求的全部接口,还有 approve 和 allowance 没有实现,但参考上述的代码,这两个接口也是很容易实现的,只要还是看项目中对于此部分的需求要求。而且一般来说,并不建议手动来实现上述的需求,可以借助 OpenZepplion 这样的项目来发行 token、nft 等。 对于一个项目,更多的还是要去思考 token economy 的设计,现在大部分的项目代币,在我看来并无意义,token 也不仅仅可以用于货币,也可以用于更多其他的场景。 ## Publication Information - [0xdoux.eth](https://paragraph.com/@0xdoux/): Publication homepage - [All Posts](https://paragraph.com/@0xdoux/): More posts from this publication - [RSS Feed](https://api.paragraph.com/blogs/rss/@0xdoux): Subscribe to updates - [Twitter](https://twitter.com/DouXin): Follow on Twitter