主页 > imtoken官网版下载 > 以太坊智能合约 [ERC20] 代币发行记录

以太坊智能合约 [ERC20] 代币发行记录

imtoken官网版下载 2023-03-24 07:23:24

以太坊之所以被称为区块链2.0,是因为以太坊在应用层提供了一个虚拟机,允许开发者基于它定制逻辑,通常被称为智能合约。 合约中的公共接口可以作为正常的交易执行。 本文完整介绍了智能合约的代币发行流程(当然智能合约不限于代币发行)。 内容如下:

SolidityERC20合约编写发布合约源码上传他人

坚固性

Solidity 是以太坊中用于编写智能合约的语言,最新版本为 0.5.11。 这里介绍几个关键概念。

图书馆

该库常用于提供可重用的方法,可以随合约发布[作为合约的一部分],但最终单独部署[到链上]并有自己的地址。 外部可以使用delegatecall方法调用库函数。

我们使用 library 关键字来创建库,这与创建合约非常相似。 但与合约不同的是,我们不能在库中定义任何存储类型的变量。 因为库只是意味着代码重用而不是状态的状态管理。

内部库函数对所有合约都是可见的。

using for: 指令使用 A for B; 用于将库 A 中定义的函数附加到任何类型 B,函数的第一个参数应该是 B 的实例。您可以使用 A for * 将库函数分配给任意类型。 库函数可以重载。 可以定义多个同名函数,但第一个参数的类型不同。 调用时,会根据调用类型自动选择某种方法。

地址索引

记录事件的索引参数将允许您使用索引参数作为过滤器来搜索这些事件。

索引关键字仅与记录的事件相关。

几个预定义字段

address.balance:地址余额,指的是该地址关联的以太坊数量。

msg.sender:交易的发送者。

this:合约地址。

msg.value:本次交易支付的以太坊金额,与payable配合使用。

似乎还有 msg.sig、msg.data、msg.gas。

应付款

修改后的函数是指调用该函数时,合约可以充值以太币(合约也是一种账户,有自己的地址)。 合约本身持有ETH,这使得用户可以更方便地基于该合约进行跨币种交易。

恒、观、纯

constant 修饰常量或函数。 当修改一个函数时,意味着该函数不修改合约状态,即不产生需要广播的交易,不消耗gas。 它通常用于读取状态或与状态无关的操作。 从0.4.17开始改为查看和纯修改函数,前者表示读取状态,后者表示状态无关。

储藏区域

storage:状态变量,会存储在链上;

内存:临时变量

interface:通过传入不同的地址实现多态。

event,应用层(web3)可以通过watch进行监听,应该是轮询的方式实现。

修饰符,一个简单的aop,编译时会替换和合并代码。

以太坊币合约地址_site163.com 以太坊币官网地址_比特币莱特币以太坊瑞波币的区别

ERC20

我们可以在智能合约中自由开发各种功能,其中相当一部分以代币合约的形式存在。 既然是token,自然有转账、余额查询等功能。 每个人都在努力为不同的代币合约开发不同的钱包,因此出现了一些规范,其中最常见的是 ERC20。

ERC20定义了几种方法,网上的资料很多,这里就不赘述了。 approve、transferFrom、allowance这三个方法有点难理解。 举个例子——A账户有1000个ETH,如果想授权B账户随意从A账户转出100ETH,需要调用approve(B,100)。 当账户 B 想使用 100 ETH 中的 10 ETH 到账户 C 时,调用 transferFrom(A, C, 10)。 此时调用allowance(A, B)查看B账户还能调用A账户多少token。

我试过好几个本地钱包和在线钱包,都支持转账,但支持授权的很少。

有人在github上总结了很多ERC20合约代码,看到基于以太坊发行的ERC20代币合约代码大合集。

合同撰写和发布

一个简单的合约demo如下:

  1 pragma solidity ^0.5.7;
  2 
  3 import './safemath.sol';
  4 
  5 contract ErbCoin {
  6     using SafeMath for uint256;
  7 
  8     string constant public name = "Mask Coin";      //  token name
  9     string constant public symbol = "MASK";           //  token symbol
 10     uint256 public decimals = 18;            //  token digit
 11 
 12     //mapping (address => uint256) public balanceOf;
 13     mapping (address => mapping (address => uint256)) public allowance; //a授权给b表示b可转账给其他人的代币数
 14     mapping (address => uint256) public frozenBalances; //冻结余额
 15     mapping (address => uint256) public balances; //可操作余额
 16 
 17     uint256 public totalSupply = 0;
 18     bool public stopped = false;
 19 
 20     //uint256 constant valueFounder = 1000000;
 21     address constant zeroaddr = address(0);

site163.com 以太坊币官网地址_比特币莱特币以太坊瑞波币的区别_以太坊币合约地址

22 address owner = zeroaddr; //合约所有者 23 address founder = zeroaddr; //初始代币持有者 24 25 modifier isOwner { 26 assert(owner == msg.sender); 27 _; 28 } 29 30 modifier isFounder { 31 assert(founder == msg.sender); 32 _; 33 } 34 35 modifier isAdmin { 36 assert(owner == msg.sender || founder == msg.sender); 37 _; 38 } 39 40 modifier isRunning { 41 assert (!stopped); 42 _; 43 } 44 45 modifier validAddress { 46 assert(zeroaddr != msg.sender); 47 _; 48 } 49

以太坊币合约地址_比特币莱特币以太坊瑞波币的区别_site163.com 以太坊币官网地址

50 constructor(address _addressFounder,uint256 _valueFounder) public { 51 owner = msg.sender; 52 founder = _addressFounder; 53 totalSupply = _valueFounder*10**decimals; 54 balances[founder] = totalSupply; 55 emit Transfer(zeroaddr, founder, totalSupply); 56 } 57 58 function balanceOf(address _owner) public view returns (uint256) { 59 //账户余额 = 可操作余额 + 被冻结余额 60 return balances[_owner] + frozenBalances[_owner]; 61 } 62 63 function transfer(address _to, uint256 _value) public isRunning validAddress returns (bool success) { 64 balances[msg.sender] = balances[msg.sender].sub(_value); 65 balances[_to] = balances[_to].add(_value); 66 emit Transfer(msg.sender, _to, _value); 67 return true; 68 } 69 70 //msg.sender 将 _from 授权给他(msg.sender)的代币转给 _to 71 function transferFrom(address _from, address _to, uint256 _value) public isRunning validAddress returns (bool success) { 72 balances[_from] = balances[_from].sub(_value); 73 //balances[_to] = balances[_to].add(_value); 74 frozenBalances[_to] = frozenBalances[_to].add(_value); //代币为冻结状态 75 allowance[_from][msg.sender] = allowance[_from][msg.sender].sub(_value); 76 emit TransferFrozen(_to, _value); 77 return true;

site163.com 以太坊币官网地址_以太坊币合约地址_比特币莱特币以太坊瑞波币的区别

78 } 79 80 //msg.sender 授权 _spender 可操作代币数 81 function approve(address _spender, uint256 _value) public isRunning isFounder returns (bool success) { 82 require(_value == 0 || allowance[msg.sender][_spender] == 0,"illegal operation"); 83 allowance[msg.sender][_spender] = _value; 84 emit Approval(msg.sender, _spender, _value); 85 return true; 86 } 87 88 //冻结部分释放 89 function release(address _target, uint256 _value) public isRunning isAdmin returns(bool){ 90 frozenBalances[_target] = frozenBalances[_target].sub(_value); 91 balances[_target] = balances[_target].add(_value); 92 emit Release(_target, _value); 93 return true; 94 } 95 96 function stop() public isAdmin { 97 stopped = true; 98 } 99 100 function start() public isAdmin { 101 stopped = false; 102 } 103 104 event Transfer(address indexed _from, address indexed _to, uint256 _value); 105 event Approval(address indexed _owner, address indexed _spender, uint256 _value);

比特币莱特币以太坊瑞波币的区别_以太坊币合约地址_site163.com 以太坊币官网地址

106 event TransferFrozen(address _target, uint256 _value); 107 event Release(address _target, uint256 _value); 108 }

查看代码

细心的朋友会发现,ERC20规范定义了函数,而这里的代码并没有name()、symbol()、decimals(),只有同名字段,因为编译器会自动将public字段编译成函数。

代码中还引入了一个库文件,避免了数值溢出导致的bug。 详情请参考ERC20 Token智能合约的SafeMath安全。

我们可以直接在浏览器端操作发布合约以太坊币合约地址,我们需要使用:

MetaMask:浏览器插件形式的以太坊钱包,可以接入主链和多条测试链。

Remix:一个用于编写、编译和发布合约的站点,可以与 MetaMask 无缝协作。

具体如何操作就不介绍了,网上资料比较多。

踩坑了,多次发token。 imToken(一个流行的钱包应用程序)上显示的令牌名称是 XXX_UNKOWN,后跟一个额外的 _UNKOWN 后缀; 只有一致才显示正常,不知道是不是名字不一致导致的问题。

另外,合约部署成功后,可以在Remix上调用合约接口。 如果知道别人的合约代码和合约地址,也可以在Remix上编译,输入地址调用,如下图:

如果知道合约的ABI,调用合约接口会更方便,如下图:

别人的合约代码和ABI从哪里来? 请看下一节。

合约源码上传

为什么要上传智能合约的代码?

代码上传是在网上完成的,目前上传很简单。 基本上就是上传代码文件(几个)然后next(不像网上有些资料需要额外输入byteCode和ABI)。 不过需要注意国内网络问题(你懂的),提交验证合约时总是提示“抱歉!我们遇到了意外错误,请稍后再试”,这是因为验证码被屏蔽了,如何操作你不需要我教你。

其他

在智能合约中,只能等待外部调用,不能执行定时任务。 同时,也不可能主动发起外部请求。

默认情况下以太坊币合约地址,geth创建的账户是锁定的,只能转入不能转出,除非解锁(geth --unlock)。 尽量避免在外部节点服务器上解锁,否则会有被盗的风险。 详细可见自己也得到了教训,还好损失不大。 实际对外提供服务的全节点可以通过做以下一项或多项来显着降低风险:

不要使用默认端口;

RPC只对内开放,对外需要网关协议转换;

帐户不存储在服务器上,或直接在服务器上使用。

助记词(BIP32/BIP39/BIP44)的原理可以参考比特币源码学习(七)——钱包的原理

其他参考:

智能合约的局限性 智能合约中最常见的 3 个误解

Solidity Doc Solidity的语法结构

实现一个具有管理、增发、兑换、冻结等高级功能的通证