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

  1. Solidity
  2. ERC20
  3. 合约编写与发布
  4. 合约源码上传
  5. 其它

Solidity

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

library

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

我们使用library关键字来创建一个library,这和创建contract十分类似。但不像contract,在library中我们不能定义任何storage类型的变量。因为library只是意味着代码的重用而不是进行state的状态管理。

internal的库函数对所有合约可见。

using for:指令using A for B;用来附着库A里定义的函数到任意类型B,函数的第一个参数应是B的实例。可以使用using A for *,将库函数赋予任意类型。库函数可以重载的,你可以定义好几个同名函数,但是第一个参数的类型不同,调用的时候自动的根据调用类型选择某一种方法。

address indexed

The indexed parameters for logged events will allow you to search for these events using the indexed parameters as filters.

The indexed keyword is only relevant to logged events.

几个预定义字段

address.balance:地址余额,指该地址相关的以太币数额。

msg.sender:交易发起人。

this:合约地址。

msg.value:发起这笔交易支付的以太币数额,和payable搭配使用。

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

payable

修饰函数,表示在调用函数时,可以给这个合约充以太币(合约也是一种账户,也有自己的地址)。合约本身持有以太币,可使得用户基于此合约进行跨币交易更方便。

constant、view、pure

constant修饰常量或函数,修饰函数时表示该函数不修改合约状态,即不产生需广播的交易,也就不会消耗gas,一般用于读状态或状态无关操作。0.4.17开始,改为view和pure修饰函数,前者表示读状态,后者表示状态无关。

存储区

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

memory:临时变量

interface:搭配传入的不同address,实现多态。

event,应用层(web3)可通过watch监听,应该是用轮询实现。

modifier,简单的aop,编译时会将代码替换合并。


ERC20

我们可以在智能合约里随意开发各种功能,相当一部分以代币合约的形式存在。既然是代币,自然有转账、余额查询等功能,大家苦于对不同的代币合约开发不同的钱包,于是有了一些规范的出现,其中最普遍的是ERC20。

ERC20定义了若干方法,网上有很多资料,这里不再赘述。稍微不好理解的是approve、transferFrom及allowance三个方法,这里举例说明——账户A有1000个ETH,想授权B账户随意调用A账户的100个ETH,则需调用approve(B,100)。当B账户想用这100个ETH中的10个ETH给C账户时,则调用transferFrom(A, C, 10)。这时调用allowance(A, B)可以查看B账户还能够调用A账户多少个token。

本人试用了若干本地钱包和在线钱包,都支持转账,但鲜有支持授权的。

有人在github上汇总了众多ERC20合约代码,see 基于以太坊发行的ERC20代币合约代码大集合


合约编写与发布

一个简单的合约demo如下:

 pragma solidity ^0.5.;

 import './safemath.sol';

 contract ErbCoin {
using SafeMath for uint256; string constant public name = "Mask Coin"; // token name
string constant public symbol = "MASK"; // token symbol
uint256 public decimals = ; // token digit //mapping (address => uint256) public balanceOf;
mapping (address => mapping (address => uint256)) public allowance; //a授权给b表示b可转账给其他人的代币数
mapping (address => uint256) public frozenBalances; //冻结余额
mapping (address => uint256) public balances; //可操作余额 uint256 public totalSupply = ;
bool public stopped = false; //uint256 constant valueFounder = 1000000;
address constant zeroaddr = address();
address owner = zeroaddr; //合约所有者
address founder = zeroaddr; //初始代币持有者 modifier isOwner {
assert(owner == msg.sender);
_;
} modifier isFounder {
assert(founder == msg.sender);
_;
} modifier isAdmin {
assert(owner == msg.sender || founder == msg.sender);
_;
} modifier isRunning {
assert (!stopped);
_;
} modifier validAddress {
assert(zeroaddr != msg.sender);
_;
} constructor(address _addressFounder,uint256 _valueFounder) public {
owner = msg.sender;
founder = _addressFounder;
totalSupply = _valueFounder***decimals;
balances[founder] = totalSupply;
emit Transfer(zeroaddr, founder, totalSupply);
} function balanceOf(address _owner) public view returns (uint256) {
//账户余额 = 可操作余额 + 被冻结余额
return balances[_owner] + frozenBalances[_owner];
} function transfer(address _to, uint256 _value) public isRunning validAddress returns (bool success) {
balances[msg.sender] = balances[msg.sender].sub(_value);
balances[_to] = balances[_to].add(_value);
emit Transfer(msg.sender, _to, _value);
return true;
} //msg.sender 将 _from 授权给他(msg.sender)的代币转给 _to
function transferFrom(address _from, address _to, uint256 _value) public isRunning validAddress returns (bool success) {
balances[_from] = balances[_from].sub(_value);
//balances[_to] = balances[_to].add(_value);
frozenBalances[_to] = frozenBalances[_to].add(_value); //代币为冻结状态
allowance[_from][msg.sender] = allowance[_from][msg.sender].sub(_value);
emit TransferFrozen(_to, _value);
return true;
} //msg.sender 授权 _spender 可操作代币数
function approve(address _spender, uint256 _value) public isRunning isFounder returns (bool success) {
require(_value == || allowance[msg.sender][_spender] == ,"illegal operation");
allowance[msg.sender][_spender] = _value;
emit Approval(msg.sender, _spender, _value);
return true;
} //冻结部分释放
function release(address _target, uint256 _value) public isRunning isAdmin returns(bool){
frozenBalances[_target] = frozenBalances[_target].sub(_value);
balances[_target] = balances[_target].add(_value);
emit Release(_target, _value);
return true;
} function stop() public isAdmin {
stopped = true;
} function start() public isAdmin {
stopped = false;
} event Transfer(address indexed _from, address indexed _to, uint256 _value);
event Approval(address indexed _owner, address indexed _spender, uint256 _value);
event TransferFrozen(address _target, uint256 _value);
event Release(address _target, uint256 _value);
}

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

代码里还import了一个库文件,是为了避免数值溢出导致的bug,具体可看关于ERC20 Token智能合约的SafeMath安全

发布合约我们可以直接在浏览器端操作,需要用到:

MetaMask:一款以浏览器插件形式存在的以太坊钱包,能接入主链和多个测试链。

Remix:https://remix.ethereum.org,编写编译发布合约的一个站点,能和MetaMask无缝合作。

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

本人踩过一个坑,发币多次在imToken(一个较流行的钱包App)上显示的代币名称都是XXX_UNKOWN,后面多了_UNKOWN后缀;后有一次将contract名称和代币name、symbol保持一致,才显示正常,但不知是否是名称不一致导致的问题。

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

如果你知道合约的ABI,那么使用https://www.myetherwallet.com调用合约接口则更方便,如下图:

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


合约源码上传

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

  • 公开token的源码,增加透明度和投资人的信任度;
  • 上传源码后,人们可以在Etherscan查看当前token的源码,同时也可以很方便的看到token的相关信息;
  • 上述所说,如果不是标准接口,市面上的各类钱包不支持,那么可以通过Remix或myetherwallet直接调用接口,而不用另外开发定制化钱包。

代码上传是在https://etherscan.io上完成的,目前上传很简单,基本上上传代码文件(有几个传几个)后next即可(不像网上有些资料说的需要另外输入byteCode和ABI)。不过需要注意的是国内网络问题(你懂的),在提交验证合约时,总是提示 “Sorry! We encountered an unexpected error. Please try back again shortly ”,这是因为验证码被墙了,如何操作不需要我教了吧。


其它

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

默认情况下,geth创建的账户是被锁住的,可以转入不能转出,除非解锁(geth --unlock)。尽量避免在对外的节点服务器上做解锁操作,否则将有被盗币的风险。具体可看金钱难寐,大盗独行——以太坊 JSON-RPC 接口多种盗币手法大揭秘,本人亦有教训,所幸损失不大。实际对外提供服务的全节点,做到以下一点或几点,就能显著降低风险:

不使用默认端口;

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

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

助记词(BIP32/BIP39/BIP44)的原理可参看 比特币源码研读(7)—— 钱包的原理

智能合约的同一个接口,gas used 未必相同,要看实际执行到的步骤和对存储的操作,规则如下:

其它参考资料:

智能合约的局限性   智能合约中存在的3种最常见的误解

Solidity Doc   solidity的语法结构

实现一个可管理、增发、兑换、冻结等高级功能的代币

以太坊中的账户、交易、Gas和区块Gas Limit

转载请注明本文出处:https://www.cnblogs.com/newton/p/11367710.html

以太坊智能合约[ERC20]发币记录的更多相关文章

  1. 以太坊智能合约介绍,Solidity介绍

    以太坊智能合约介绍,Solidity介绍 一个简单的智能合约 先从一个非常基础的例子开始,不用担心你现在还一点都不了解,我们将逐步了解到更多的细节. Storage contract SimpleSt ...

  2. 如何通过以太坊智能合约来进行众筹(ICO)

    前面我们有两遍文章写了如何发行代币,今天我们讲一下如何使用代币来公开募资,即编写一个募资合约. 写在前面 本文所讲的代币是使用以太坊智能合约创建,阅读本文前,你应该对以太坊.智能合约有所了解,如果你还 ...

  3. 深入以太坊智能合约 ABI

    开发 DApp 时要调用在区块链上的以太坊智能合约,就需要智能合约的 ABI.本文希望更多了解 ABI,如为什么需要 ABI?如何解读 Ethereum 的智能合约 ABI?以及如何取得合约的 ABI ...

  4. Go语言打造以太坊智能合约测试框架(level1)

    传送门: 柏链项目学院 Go语言打造以太坊智能合约测试框架 前言 这是什么? 这是一个基于go语言编写的,自动化测试以太坊智能合约的开发框架,使用此框架,可以自动化的部署合约,自动测试合约内的功能函数 ...

  5. 以太坊智能合约 Solidity 的常用数据类型介绍

    目录 目录 1.数组 1.1.对数组的增删改查操作. 2.String.Bytes.Mapping的使用 3.Enums 和 Structs 的简单应用 4.Ether 单位和 Time 单位 5.A ...

  6. 以太坊智能合约Hello World示例程序

    简介 以太坊(Ethereum)是一提供个智能合约(smart contract)功能的公共区块链(BlockChain)平台. 本文介绍了一个简单的以太坊智能合约的开发过程. 开发环境 在以太坊上开 ...

  7. Go语言打造以太坊智能合约测试框架(level3)

    传送门: 柏链项目学院 第三课 智能合约自动化测试 之前课程回顾 我们之前介绍了go语言调用exec处理命令行,介绍了toml配置文件的处理,以及awk处理文本文件获得ABI信息.我们的代码算是完成了 ...

  8. rpc接口调用以太坊智能合约

    rpc接口调用以太坊智能合约 传送门: 柏链项目学院   在以太坊摸爬滚打有些日子了,也遇到了各种各样的问题.这几天主要研究了一下如何通过rpc接口编译.部署和调用合约.也遇到了一些困难和问题,下面将 ...

  9. 使用web3.js监听以太坊智能合约event

    传送门: 柏链项目学院 使用web3.js监听以太坊智能合约event   当我们在前端页面调用合约时发现有些数据不会立即返回,这时还需要再调用更新数据的函数.那么这样的方法使用起来非常不便,监听ev ...

随机推荐

  1. Flutter学习笔记(10)--容器组件、图片组件

    如需转载,请注明出处:Flutter学习笔记(10)--容器组件.图片组件 上一篇Flutter学习笔记(9)--组件Widget我们说到了在Flutter中一个非常重要的理念"一切皆为组件 ...

  2. ArcGIS API For JavaScript 开发(五)要素图层的编辑

    2018-4-3 这篇博客主要讲述要素的层的编辑功能,是基于FeatureLayer的applyEdit方法.由于自己目前正在学习当中,有许多不足之处请各位指出,欢迎指导学习! 主要功能是 1.将地图 ...

  3. python基础——字典(dict)

    字典是另一种可变容器模型,且可存储任意类型对象. 字典的每个键值(key=>value)对用冒号(:)分割,每个对之间用逗号(,)分割,整个字典包括在花括号({})中 . dict1 = {} ...

  4. 动态规划_Sumsets_POJ-2229

    Farmer John commanded his cows to search . Here are the possible sets of numbers that sum to : ) +++ ...

  5. 05-k8s调度器、预选策略、优选函数

    目录 k8s调度器.预选策略.优选函数 节点选择过程 调度器 预选策略 优选函数 高级调度设置机制 node选择器/node亲和调度 pod亲和性 污点调度 Taints 与 Tolerations ...

  6. 百度网盘 人工智能书籍【Tensorflow和深度学习】

    链接:https://pan.baidu.com/s/1ejCvwn08ILI2fMhBEdXR8w 提取码:6pk9

  7. Java集合系列(一)List集合

    List的几种实现的区别与联系 List主要有ArrayList.LinkedList与Vector几种实现. ArrayList底层数据结构是数组, 增删慢.查询快; 线程不安全, 效率高; 不可以 ...

  8. DataPipeline丨DataOps理念与设计原则

    作者:DataPipeline CEO 陈诚 上周我们探讨了数据的「资产负债表」与「现状」,期间抛给大家一个问题:如果我们制作一个企业的“数据资产负债表”,到底会有多少数据是企业真正的资产? 数据出现 ...

  9. 【Kubernetes 系列一】Kubernetes 概述

    以下内容还可以通过 Google Slide 查看:https://docs.google.com/presentation/d/1eYP4bkVBojI_e6PqdpxIf0hvWO-JwAf-fy ...

  10. 2月11日 阿里巴巴Java开发手册 读后感

    该手册分为几个部分: 印象深刻的几点: (五)集合处理 2.[强制]ArrayList的subList结果不可强转成ArrayList,否则会抛出ClassCastException 异常:java. ...