您的位置:首页 > 编程语言 > Go语言

Go-Ethereum 结合 Mist 0.9.2 实现代币智能合约的实例

2018-01-20 16:01 489 查看

目录

Contents [hide]目录1、什么是 Mist2、Mist 在哪里下载?3、Mist 有哪些依赖?4、如何安装 Mist?4.1、安装 Mist 依赖工具包4.2、安装 Mist4.3、启动 Mist,连接到 Geth5、使用 Mist 部署一个简单的智能合约6、改善代币6.1、如何部署7、高级版的代币功能7.1、去中心化的管理者7.2、挖矿7.3、冻结资产7.4、自动交易7.5、全部代码7.6、使用以太币购买代币7.7、卖出代币8、常见问题8.1、在调试Mist的过程中,创建了很多个合约,如何删除?

1、什么是 Mist

  
Mist
是以太坊官方的在线钱包管理工具。通过 
Mist
 我们可以很方便的连接上我们的私有网络,从而更好的开发、调试、测试我们的智能合约。既可以连接生产网络、测试网络,更加可以通过设置参数的方式,连接我们自己的私有网络。  
Mist
 在通过 
geth.ipc
 文件连接后,就和 
Geth
 所建立的网络完全契合在一起了,在 
Mist
 上部署的合约,实际上也就是部署在了 
Geth
 网络上。
Geth
 网络上新建账号,也可以在 
Mist
 这个工具上看到。  通过 
Mist
,我们向大家更详细的讲解了以太坊的核心概念,包括:区块、Transaction、Gas、账户、合约、合约中的构造函数,变量以及方法。  

2、Mist 在哪里下载?

  开发版的 
Mist
 在这里下载:https://github.com/ethereum/mist  如果要在生产环境上操作,可以直接在以太坊官网下载钱包工具:https://ethereum.org/  

3、Mist 有哪些依赖?

  需要有以下组件:Node.js 
v7.x
 (use the prefered installation method for your OS)Meteor javascript app frameworkYarn package managerElectron 
v1.7.9
 cross platform desktop app frameworkGulp build and automation system  

4、如何安装 Mist?

  在安装 
Mist
 前,要先安装依赖的工具包。  

4.1、安装 Mist 依赖工具包

➜ /Users/lion >curl https://install.meteor.com/ ➜ /Users/lion >brew install yarn
➜ /Users/lion >yarn global add electron@1.7.9
➜ /Users/lion >yarn global add gulp
yarn其他平台的安装方法,可以参考:https://yarnpkg.com/zh-Hans/docs/install  

4.2、安装 Mist

➜ /Users/lion/my_project/_eth >git clone https://github.com/ethereum/mist.git ➜ /Users/lion/my_project/_eth >cd mist
➜ /Users/lion/my_project/_eth/mist git:(develop) >git checkout v0.9.2
➜ /Users/lion/my_project/_eth/mist git:(369713b) >yarn
  

4.3、启动 Mist,连接到 Geth

  新开一个窗口,用以下命令运行 
Mist
 的后台程序:
➜ /Users/lion/my_project/_eth/mist git:(369713b) >cd interface
➜ /Users/lion/my_project/_eth/mist/interface git:(369713b) >meteor --no-release-check
[[[[[ ~/my_project/_eth/mist/interface ]]]]]

=> Started proxy.
=> Started MongoDB.
=> Started your app.

=> App running at: http://localhost:3000/ => Client modified -- refreshing
第一次运行会慢一些,会启动proxy、MongoDB等程序,同时下载一些依赖组件    在启动 
Mist
 之前,我们要先启动 
Geth
,参考:使用 Go-Ethereum 1.7.2搭建以太坊私有链  我们启用以太坊私有链以后,在 
./chain
 目录上会创建私有链的一些数据,里面有一个 
geth.ipc
 文件。
➜ /Users/lion/my_project/_eth/test >ll chain
total 88
drwxr-xr-x  7 lion  staff    224 Oct 24 12:21 geth
srw-------  1 lion  staff      0 Oct 24 12:24 geth.ipc
-rw-------  1 lion  staff  43213 Oct 24 12:08 history
drwx------  4 lion  staff    128 Oct 22 14:57 keystore
    在原来的窗口中运行以下命令,用 
Mist
 连接我们用 
Geth
 启动的私有链:
➜ /Users/lion/my_project/_eth/mist git:(369713b) >yarn dev:electron --rpc /Users/lion/my_project/_eth/test/chain/geth.ipc
如果正常交易以太坊的以太币,可以在官网直接下载以太坊钱包使用:https://ethereum.org/    如果在另一台机器是使用RPC方式运行,也可以使用下面的方法连接到 
Geth
➜ /Users/lion/my_project/_eth/mist git:(369713b) >yarn dev:electron --rpc http://localhost:8545
    运行完以后,会打开一个比较像App的网页,如下图:在之前的文章中我们创建的帐户,经过 
Mist
 连接后,也可以在可视化的界面中看到    在 
Mist
 的界面中,点击发送,可以从一个帐户地址,向另一个帐户地址,转移以太币。  

5、使用 Mist 部署一个简单的智能合约

  在 
Mist
 上点击右侧的合约。首先要选择一个帐户来生成合约,用于支付部署合约的费用,以后是谁调用谁来支付费用。(如果在公有链上部署智能合约,需要花费一定的以太币)。  下面是一个最简单的合约代码,主要介绍可以看注释:  
pragma solidity 0.4.16;

/**
* @title 基础版的代币合约
*/
contract token {
/* 公共变量 */
string public standard = 'https://mshk.top';

/*记录所有余额的映射*/
mapping (address => uint256) public balanceOf;

/* 初始化合约,并且把初始的所有代币都给这合约的创建者
* @param initialSupply 代币的总数
*/
function token(uint256 initialSupply) {
//给指定帐户初始化代币总量,初始化用于奖励合约创建者
balanceOf[msg.sender] = initialSupply;
}

/**
* 私有方法从一个帐户发送给另一个帐户代币
* @param  _from address 发送代币的地址
* @param  _to address 接受代币的地址
* @param  _value uint256 接受代币的数量
*/
function _transfer(address _from, address _to, uint256 _value) internal {

//避免转帐的地址是0x0
require(_to != 0x0);

//检查发送者是否拥有足够余额
require(balanceOf[_from] >= _value);

//检查是否溢出
require(balanceOf[_to] + _value > balanceOf[_to]);

//保存数据用于后面的判断
uint previousBalances = balanceOf[_from] + balanceOf[_to];

//从发送者减掉发送额
balanceOf[_from] -= _value;

//给接收者加上相同的量
balanceOf[_to] += _value;

//判断买、卖双方的数据是否和转换前一致
assert(balanceOf[_from] + balanceOf[_to] == previousBalances);

}

/**
* 从主帐户合约调用者发送给别人代币
* @param  _to address 接受代币的地址
* @param  _value uint256 接受代币的数量
*/
function transfer(address _to, uint256 _value) public {
_transfer(msg.sender, _to, _value);
}
}
    接下来我们将上面的合约代码,通过Mist部署到我们的私有链的。  首先如下图中,点击
合约
->
部署新合约
    然后如下面的两张图,选择创建合约的帐户,将上面的代码贴到
SOLIDITY合约原始代码
处,在右侧选择要部署的合约
token
,在
token
的下面
Initial Supply
处,输入我们要初始化的金额
5000
用于奖励合约创建者,然后在页面的最下面,点击部署,的弹出的层中,输入创建合约这个帐号的密码,输入正确以后,合约创建成功。    创建一个合约以后,再点击 
Mist
 右侧的合约,然后在 
定制化合约
 的下面,可以看到我们刚刚创建的合约 
TOKEN
 ,如下图:注意,在合约下面也有一串
0x
开头的地址,这个就相当于一个钱包的地址。在以太坊中,合约也相当于一个帐户    点击 
TOKEN
 ,进入到合约里。在下面的 
Balance Of
 处,输入刚才创建合约帐户的地址
0xa18e688326ab13b6147ce3ca2213db143a4ec2ee
,可以看到是有5000个代币在里面,如下图:    在代币创建的时候,初始值我们设置的是5000,所以只有创建帐户的地址有代币,而输入其他帐户的地址,如
0xc81896af13449a82f22699311df4ec4b48c07718
,是没有值的。  接下来,我们向
0xc81896af13449a82f22699311df4ec4b48c07718
这个帐户地址,转入一些代币。点击右侧
选择函数
->选择
Transfer
,在
_to
中输入
0xc81896af13449a82f22699311df4ec4b48c07718
,在
_value
中输入
500
,然后点击执行,在弹出的层中输入调用合约帐户的密码,确认操作。我们能够看到实际调用合约的过程中,会花费一定的
gas
gas
和以太币会根据区块的算力有一个计算公式,
gas
一般用于奖励给挖矿者    在 
transfer
 方法中,我们设定了,只有合约的调用者
msg.sender
才能向指定地址转移代币。
/**
* 从主帐户合约调用者发送给别人代币
* @param  _to address 接受代币的地址
* @param  _value uint256 接受代币的数量
*/
function transfer(address _to, uint256 _value) public {
_transfer(msg.sender, _to, _value);
}
    这时,再次进入合约,在
Balance Of
处,输入两个帐户的地址,可以看到,余额都发生的变化,如下图:  

6、改善代币

  通过上面的操作,我们已经可以将合约代码,通过 
Mist
 部署到我们创建的私有链中,同样如果部署到生产环境,只需要连上以太坊的网络,同样的方法也可以将你的合约,部署到生产环境中,不过要根据代码的大小,花费一些以太币。  实际使用过程中,交易的过程,需要通知到客户端,并且记录到区块中,我们可以使用
event
事件来指定,如下代码进行声明:
//在区块链上创建一个事件,用以通知客户端
event Transfer(address indexed from, address indexed to, uint256 value);
    设置一些代币的基本信息
/* 公共变量 */
string public standard = 'https://mshk.top';
string public name; //代币名称
string public symbol; //代币符号比如'$'
uint8 public decimals = 18;  //代币单位,展示的小数点后面多少个0,和以太币一样后面是是18个0
uint256 public totalSupply; //代币总量
    某些特定的场景中,不允许某个帐户花费超过指定的上限,避免大额支出,我们可以添加一个 
approve
 方法,来设置一个允许支出最大金额的列表。
mapping (address => mapping (address => uint256)) public allowance;

/**
* 设置帐户允许支付的最大金额
*
* 一般在智能合约的时候,避免支付过多,造成风险
*
* @param _spender 帐户地址
* @param _value 金额
*/
function approve(address _spender, uint256 _value) public returns (bool success) {
allowance[msg.sender][_spender] = _value;
return true;
}
    同样在 
solidity
 中,合约之间也可以相互调用,我们可以增加一个 
approveAndCall
 方法,用于在设置帐户最大支出金额后,可以做一些其他操作。
interface tokenRecipient { function receiveApproval(address _from, uint256 _value, address _token, bytes _extraData) public; }

/**
* 设置帐户允许支付的最大金额
*
* 一般在智能合约的时候,避免支付过多,造成风险
*
* @param _spender 帐户地址
* @param _value 金额
*/
function approve(address _spender, uint256 _value) public returns (bool success) {
allowance[msg.sender][_spender] = _value;
return true;
}

/**
* 设置帐户允许支付的最大金额
*
* 一般在智能合约的时候,避免支付过多,造成风险,加入时间参数,可以在 tokenRecipient 中做其他操作
*
* @param _spender 帐户地址
* @param _value 金额
* @param _extraData 操作的时间
*/
function approveAndCall(address _spender, uint256 _value, bytes _extraData) public returns (bool success) {
tokenRecipient spender = tokenRecipient(_spender);
if (approve(_spender, _value)) {
spender.receiveApproval(msg.sender, _value, this, _extraData);
return true;
}
}
    我们可以增加一个 
burn
 方法,用于管理员减去指定帐户的指定金额。进行该方法操作时,通知客户端记录到区块链中。
//减去用户余额事件
event Burn(address indexed from, uint256 value);

/**
* 减少代币调用者的余额
*
* 操作以后是不可逆的
*
* @param _value 要删除的数量
*/
function burn(uint256 _value) public returns (bool success) {
//检查帐户余额是否大于要减去的值
require(balanceOf[msg.sender] >= _value);   // Check if the sender has enough

//给指定帐户减去余额
balanceOf[msg.sender] -= _value;

//代币问题做相应扣除
totalSupply -= _value;

Burn(msg.sender, _value);
return true;
}

/**
* 删除帐户的余额(含其他帐户)
*
* 删除以后是不可逆的
*
* @param _from 要操作的帐户地址
* @param _value 要减去的数量
*/
function burnFrom(address _from, uint256 _value) public returns (bool success) {

//检查帐户余额是否大于要减去的值
require(balanceOf[_from] >= _value);

//检查 其他帐户 的余额是否够使用
require(_value <= allowance[_from][msg.sender]);

//减掉代币
balanceOf[_from] -= _value;
allowance[_from][msg.sender] -= _value;

//更新总量
totalSupply -= _value;
Burn(_from, _value);
return true;
}
    完整的代码如下:
pragma solidity 0.4.16;interface tokenRecipient { function receiveApproval(address _from, uint256 _value, address _token, bytes _extraData) public; }/*** @title 基础版的代币合约*/contract token {/* 公共变量 */
string public standard = 'https://mshk.top';
string public name; //代币名称
string public symbol; //代币符号比如'$'
uint8 public decimals = 18;  //代币单位,展示的小数点后面多少个0,和以太币一样后面是是18个0
uint256 public totalSupply; //代币总量/*记录所有余额的映射*/mapping (address => uint256) public balanceOf;mapping (address => mapping (address => uint256)) public allowance;/* 在区块链上创建一个事件,用以通知客户端*/event Transfer(address indexed from, address indexed to, uint256 value);  //转帐通知事件event Burn(address indexed from, uint256 value);  //减去用户余额事件/* 初始化合约,并且把初始的所有代币都给这合约的创建者* @param initialSupply 代币的总数* @param tokenName 代币名称* @param tokenSymbol 代币符号*/function token(uint256 initialSupply, string tokenName, string tokenSymbol) {//初始化总量totalSupply = initialSupply * 10 ** uint256(decimals);    //以太币是10^18,后面18个0,所以默认decimals是18//给指定帐户初始化代币总量,初始化用于奖励合约创建者balanceOf[msg.sender] = totalSupply;name = tokenName;symbol = tokenSymbol;}/*** 私有方法从一个帐户发送给另一个帐户代币* @param  _from address 发送代币的地址* @param  _to address 接受代币的地址* @param  _value uint256 接受代币的数量*/function _transfer(address _from, address _to, uint256 _value) internal {//避免转帐的地址是0x0require(_to != 0x0);//检查发送者是否拥有足够余额require(balanceOf[_from] >= _value);//检查是否溢出require(balanceOf[_to] + _value > balanceOf[_to]);//保存数据用于后面的判断uint previousBalances = balanceOf[_from] + balanceOf[_to];//从发送者减掉发送额balanceOf[_from] -= _value;//给接收者加上相同的量balanceOf[_to] += _value;//通知任何监听该交易的客户端Transfer(_from, _to, _value);//判断买、卖双方的数据是否和转换前一致assert(balanceOf[_from] + balanceOf[_to] == previousBalances);}/**
* 从主帐户合约调用者发送给别人代币
* @param  _to address 接受代币的地址
* @param  _value uint256 接受代币的数量
*/
function transfer(address _to, uint256 _value) public {
_transfer(msg.sender, _to, _value);
}/*** 从某个指定的帐户中,向另一个帐户发送代币** 调用过程,会检查设置的允许最大交易额** @param  _from address 发送者地址* @param  _to address 接受者地址* @param  _value uint256 要转移的代币数量* @return success        是否交易成功*/function transferFrom(address _from, address _to, uint256 _value) returns (bool success) {//检查发送者是否拥有足够余额require(_value <= allowance[_from][msg.sender]);   // Check allowanceallowance[_from][msg.sender] -= _value;_transfer(_from, _to, _value);return true;}/*** 设置帐户允许支付的最大金额** 一般在智能合约的时候,避免支付过多,造成风险** @param _spender 帐户地址* @param _value 金额*/function approve(address _spender, uint256 _value) public returns (bool success) {allowance[msg.sender][_spender] = _value;return true;}/*** 设置帐户允许支付的最大金额** 一般在智能合约的时候,避免支付过多,造成风险,加入时间参数,可以在 tokenRecipient 中做其他操作** @param _spender 帐户地址* @param _value 金额* @param _extraData 操作的时间*/function approveAndCall(address _spender, uint256 _value, bytes _extraData) public returns (bool success) {tokenRecipient spender = tokenRecipient(_spender);if (approve(_spender, _value)) {spender.receiveApproval(msg.sender, _value, this, _extraData);return true;}}/*** 减少代币调用者的余额** 操作以后是不可逆的** @param _value 要删除的数量*/function burn(uint256 _value) public returns (bool success) {//检查帐户余额是否大于要减去的值require(balanceOf[msg.sender] >= _value);   // Check if the sender has enough//给指定帐户减去余额balanceOf[msg.sender] -= _value;//代币问题做相应扣除totalSupply -= _value;Burn(msg.sender, _value);return true;}/*** 删除帐户的余额(含其他帐户)** 删除以后是不可逆的** @param _from 要操作的帐户地址* @param _value 要减去的数量*/function burnFrom(address _from, uint256 _value) public returns (bool success) {//检查帐户余额是否大于要减去的值require(balanceOf[_from] >= _value);//检查 其他帐户 的余额是否够使用require(_value <= allowance[_from][msg.sender]);//减掉代币balanceOf[_from] -= _value;allowance[_from][msg.sender] -= _value;//更新总量totalSupply -= _value;Burn(_from, _value);return true;}}
  

6.1、如何部署

  如上面的部署中,我们将完整的代码,贴到 
Mist
 的 
solidity合约原始代码
 处,在右侧选择 
token
 , 
Initial Supply
 输入初始金额
5000
Token name
 输入我们的代币名称 
陌上花开
 , 
Token symbol
 代币符号我们输入 
$$
,然后点击 
部署
,输入部署帐户的密码。    部署合约以后,我们能够在合约页面看到刚才创建的合约。    点击合约名称,可以看到合约的一些基本信息,以及合约和操作函数    我们能够在 
Mist
 上方的 
钱包
 中的主帐号这里看到有个小图标,说明主帐户已经有了代币,其他帐户是没有这个图标的    点击进入主帐号以后,我们就可以看到主帐户已经拥有的代币和以太币的数量,因为我们是参考以太币进行设置,最小单位是wei,所以小数点后面有18个0。    接下来,我们向另一个帐户发送一些 
陌上花开
 币,点击 
Mist
 上方的发送,输入发送的帐户地址,输入数量 
500
,选择发送的是 
陌上花开
 币,点击发送,如下图    再次回到钱包中,我们可以看到,另一个帐户也有了一个代币的图标,说明代币已经转入成功。    现在你拥有了自己的代币,也可以做转入转出操作。可以被用于价值交换,或者工作时间追踪或者其他项目。  

7、高级版的代币功能

  一般的代币可以不设置管理者,就是所谓的去中心化。实际使用过程中,可能需要给予挖矿等功能,让别人能够购买你的代币,那么我们就需要设置一个帐户地址做为这个代币合约的管理者。
**
* owned 是一个管理者
*/
contract owned {
address public owner;

/**
* 初台化构造函数
*/
function owned() {
owner = msg.sender;
}

/**
* 判断当前合约调用者是否是管理员
*/
modifier onlyOwner {
require (msg.sender == owner);
_;
}

/**
* 指派一个新的管理员
* @param  newOwner address 新的管理员帐户地址
*/
function transferOwnership(address newOwner) onlyOwner {
owner = newOwner;
}
}
    上面的代码是一个非常简单的合约,我们可以在后面的代码中,使用 
继承
 来实现后续的功能。
/**
* @title 高级版代币
* 增加冻结用户、挖矿、根据指定汇率购买(售出)代币价格的功能
*/
contract MyAdvancedToken is owned{}
  在 
MyAdvancedToken
 的所有方法中,可以使用 
owned
 的变量 
owner
和 
modifier onlyOwner
。  

7.1、去中心化的管理者

  我们也可以在构造函数中设置是否需要一个去中心化的管理者。
/*初始化合约,并且把初始的所有的令牌都给这合约的创建者
* @param initialSupply 所有币的总数
* @param tokenName 代币名称
* @param tokenSymbol 代币符号
* @param centralMinter 是否指定其他帐户为合约所有者,为0是去中心化
*/
function MyAdvancedToken(
uint256 initialSupply,
string tokenName,
string tokenSymbol,
address centralMinter
)  {
//设置合约的管理者
if(centralMinter != 0 ) owner = centralMinter;
}
  

7.2、挖矿

  有的时候需要更多的代币流通,可以增加 
mintToken
 方法,创造更多的代币。
/**
* 合约拥有者,可以为指定帐户创造一些代币
* @param  target address 帐户地址
* @param  mintedAmount uint256 增加的金额(单位是wei)
*/
function mintToken(address target, uint256 mintedAmount) onlyOwner {

//给指定地址增加代币,同时总量也相加
balanceOf[target] += mintedAmount;
totalSupply += mintedAmount;
}
    在方法的最后有一个 
onlyOwner
,说明 
mintToken
 是继承了 
onlyOwner
方法,会先调用 
modifier onlyOwner
 方法,然后将 
mintToken
 方法的内容,插入到下划线 
_
 处调用。  

7.3、冻结资产

  有的场景中,某些用户违反了规定,需要冻结/解冻帐户,不想让他使用已经拥有的代币.可以增加以下代码来控制:
//是否冻结帐户的列表
mapping (address => bool) public frozenAccount;

//定义一个事件,当有资产被冻结的时候,通知正在监听事件的客户端
event FrozenFunds(address target, bool frozen);

/**
* 增加冻结帐户名称
*
* 你可能需要监管功能以便你能控制谁可以/谁不可以使用你创建的代币合约
*
* @param  target address 帐户地址
* @param  freeze bool    是否冻结
*/
function freezeAccount(address target, bool freeze) onlyOwner {
frozenAccount[target] = freeze;
FrozenFunds(target, freeze);
}
  

7.4、自动交易

  到了现在,代币的功能很完善,大家也相信你的代币是有价值的,但你想要使用以太币 
ether
 或者其他代币来购买,让代币市场化,可以真实的交易,我们可以设置一个价格
//卖出的汇率,一个代币,可以卖出多少个以太币,单位是wei
uint256 public sellPrice;

//买入的汇率,1个以太币,可以买几个代币
uint256 public buyPrice;

/**
* 设置买卖价格
*
* 如果你想让ether(或其他代币)为你的代币进行背书,以便可以市场价自动化买卖代币,我们可以这么做。如果要使用浮动的价格,也可以在这里设置
*
* @param newSellPrice 新的卖出价格
* @param newBuyPrice 新的买入价格
*/
function setPrices(uint256 newSellPrice, uint256 newBuyPrice) onlyOwner {
sellPrice = newSellPrice;
buyPrice = newBuyPrice;
}
    然后增加买、卖的方法,每一次的交易,都会消耗掉一定的 
ether
。在 
Solidity 0.4.0
 之后,要接收 
ether
 的函数都要加一个 
payable
 属性,如果你开放的合约,需要别人转钱给你,就需要加 
payable
。  下面的方法,不会增加代币,只是改变调用合约者的代币数量,买、卖的价格单位不是 
ether
,而是 
wei
,这是以太币中最小的单位(就像美元里的美分,比特币里的聪)。1 ether = 1000000000000000000 wei。因此使用 
ether
 设置价格的时候,在最后加18个0。  当创建合约的时候,发送足够多的 
ether
 作为代币的背书
,否则你的合约就是破产的,你的用户就不能够卖掉他们的代币。
/**
* 使用以太币购买代币
*/
function buy() payable public {
uint amount = msg.value / buyPrice;

_transfer(this, msg.sender, amount);
}

/**
* @dev 卖出代币
* @return 要卖出的数量(单位是wei)
*/
function sell(uint256 amount) public {

//检查合约的余额是否充足
require(this.balance >= amount * sellPrice);

_transfer(msg.sender, this, amount);

msg.sender.transfer(amount * sellPrice);
}
  

7.5、全部代码

  把所有的特性加上,完整的代码如下:
pragma solidity 0.4.16;interface tokenRecipient { function receiveApproval(address _from, uint256 _value, address _token, bytes _extraData) public; }/**
* owned 是一个管理者
*/
contract owned {
address public owner;

/**
* 初台化构造函数
*/
function owned() {
owner = msg.sender;
}

/**
* 判断当前合约调用者是否是管理员
*/
modifier onlyOwner {
require (msg.sender == owner);
_;
}

/**
* 指派一个新的管理员
* @param  newOwner address 新的管理员帐户地址
*/
function transferOwnership(address newOwner) onlyOwner {
owner = newOwner;
}
}/*** @title 基础版的代币合约*/contract token {/* 公共变量 */
string public standard = 'https://mshk.top';
string public name; //代币名称
string public symbol; //代币符号比如'$'
uint8 public decimals = 18;  //代币单位,展示的小数点后面多少个0,和以太币一样后面是是18个0
uint256 public totalSupply; //代币总量/*记录所有余额的映射*/mapping (address => uint256) public balanceOf;mapping (address => mapping (address => uint256)) public allowance;/* 在区块链上创建一个事件,用以通知客户端*/event Transfer(address indexed from, address indexed to, uint256 value);  //转帐通知事件event Burn(address indexed from, uint256 value);  //减去用户余额事件/* 初始化合约,并且把初始的所有代币都给这合约的创建者* @param initialSupply 代币的总数* @param tokenName 代币名称* @param tokenSymbol 代币符号*/function token(uint256 initialSupply, string tokenName, string tokenSymbol) {//初始化总量totalSupply = initialSupply * 10 ** uint256(decimals);    //以太币是10^18,后面18个0,所以默认decimals是18//给指定帐户初始化代币总量,初始化用于奖励合约创建者//balanceOf[msg.sender] = totalSupply;balanceOf[this] = totalSupply;name = tokenName;symbol = tokenSymbol;}/*** 私有方法从一个帐户发送给另一个帐户代币* @param  _from address 发送代币的地址* @param  _to address 接受代币的地址* @param  _value uint256 接受代币的数量*/function _transfer(address _from, address _to, uint256 _value) internal {//避免转帐的地址是0x0require(_to != 0x0);//检查发送者是否拥有足够余额require(balanceOf[_from] >= _value);//检查是否溢出require(balanceOf[_to] + _value > balanceOf[_to]);//保存数据用于后面的判断uint previousBalances = balanceOf[_from] + balanceOf[_to];//从发送者减掉发送额balanceOf[_from] -= _value;//给接收者加上相同的量balanceOf[_to] += _value;//通知任何监听该交易的客户端Transfer(_from, _to, _value);//判断买、卖双方的数据是否和转换前一致assert(balanceOf[_from] + balanceOf[_to] == previousBalances);}/**
* 从主帐户合约调用者发送给别人代币
* @param  _to address 接受代币的地址
* @param  _value uint256 接受代币的数量
*/
function transfer(address _to, uint256 _value) public {
_transfer(msg.sender, _to, _value);
}/*** 从某个指定的帐户中,向另一个帐户发送代币** 调用过程,会检查设置的允许最大交易额** @param  _from address 发送者地址* @param  _to address 接受者地址* @param  _value uint256 要转移的代币数量* @return success        是否交易成功*/function transferFrom(address _from, address _to, uint256 _value) returns (bool success) {//检查发送者是否拥有足够余额require(_value <= allowance[_from][msg.sender]);   // Check allowanceallowance[_from][msg.sender] -= _value;_transfer(_from, _to, _value);return true;}/*** 设置帐户允许支付的最大金额** 一般在智能合约的时候,避免支付过多,造成风险** @param _spender 帐户地址* @param _value 金额*/function approve(address _spender, uint256 _value) public returns (bool success) {allowance[msg.sender][_spender] = _value;return true;}/*** 设置帐户允许支付的最大金额** 一般在智能合约的时候,避免支付过多,造成风险,加入时间参数,可以在 tokenRecipient 中做其他操作** @param _spender 帐户地址* @param _value 金额* @param _extraData 操作的时间*/function approveAndCall(address _spender, uint256 _value, bytes _extraData) public returns (bool success) {tokenRecipient spender = tokenRecipient(_spender);if (approve(_spender, _value)) {spender.receiveApproval(msg.sender, _value, this, _extraData);return true;}}/*** 减少代币调用者的余额** 操作以后是不可逆的** @param _value 要删除的数量*/function burn(uint256 _value) public returns (bool success) {//检查帐户余额是否大于要减去的值require(balanceOf[msg.sender] >= _value);   // Check if the sender has enough//给指定帐户减去余额balanceOf[msg.sender] -= _value;//代币问题做相应扣除totalSupply -= _value;Burn(msg.sender, _value);return true;}/*** 删除帐户的余额(含其他帐户)** 删除以后是不可逆的** @param _from 要操作的帐户地址* @param _value 要减去的数量*/function burnFrom(address _from, uint256 _value) public returns (bool success) {//检查帐户余额是否大于要减去的值require(balanceOf[_from] >= _value);//检查 其他帐户 的余额是否够使用require(_value <= allowance[_from][msg.sender]);//减掉代币balanceOf[_from] -= _value;allowance[_from][msg.sender] -= _value;//更新总量totalSupply -= _value;Burn(_from, _value);return true;}/*** 匿名方法,预防有人向这合约发送以太币*//*function() {//return;     // Prevents accidental sending of ether}*/}/*** @title 高级版代币* 增加冻结用户、挖矿、根据指定汇率购买(售出)代币价格的功能*/contract MyAdvancedToken is owned, token {//卖出的汇率,一个代币,可以卖出多少个以太币,单位是weiuint256 public sellPrice;//买入的汇率,1个以太币,可以买几个代币uint256 public buyPrice;//是否冻结帐户的列表mapping (address => bool) public frozenAccount;//定义一个事件,当有资产被冻结的时候,通知正在监听事件的客户端event FrozenFunds(address target, bool frozen);/*初始化合约,并且把初始的所有的令牌都给这合约的创建者* @param initialSupply 所有币的总数* @param tokenName 代币名称* @param tokenSymbol 代币符号* @param centralMinter 是否指定其他帐户为合约所有者,为0是去中心化*/function MyAdvancedToken(uint256 initialSupply,string tokenName,string tokenSymbol,address centralMinter) token (initialSupply, tokenName, tokenSymbol) {//设置合约的管理者if(centralMinter != 0 ) owner = centralMinter;sellPrice = 2;     //设置1个单位的代币(单位是wei),能够卖出2个以太币buyPrice = 4;      //设置1个以太币,可以买0.25个代币}/*** 私有方法,从指定帐户转出余额* @param  _from address 发送代币的地址* @param  _to address 接受代币的地址* @param  _value uint256 接受代币的数量*/function _transfer(address _from, address _to, uint _value) internal {//避免转帐的地址是0x0require (_to != 0x0);//检查发送者是否拥有足够余额require (balanceOf[_from] > _value);//检查是否溢出require (balanceOf[_to] + _value > balanceOf[_to]);//检查 冻结帐户require(!frozenAccount[_from]);require(!frozenAccount[_to]);//从发送者减掉发送额balanceOf[_from] -= _value;//给接收者加上相同的量balanceOf[_to] += _value;//通知任何监听该交易的客户端Transfer(_from, _to, _value);}/*** 合约拥有者,可以为指定帐户创造一些代币* @param  target address 帐户地址* @param  mintedAmount uint256 增加的金额(单位是wei)*/function mintToken(address target, uint256 mintedAmount) onlyOwner {//给指定地址增加代币,同时总量也相加balanceOf[target] += mintedAmount;totalSupply += mintedAmount;Transfer(0, this, mintedAmount);Transfer(this, target, mintedAmount);}/*** 增加冻结帐户名称** 你可能需要监管功能以便你能控制谁可以/谁不可以使用你创建的代币合约** @param  target address 帐户地址* @param  freeze bool    是否冻结*/function freezeAccount(address target, bool freeze) onlyOwner {frozenAccount[target] = freeze;FrozenFunds(target, freeze);}/*** 设置买卖价格** 如果你想让ether(或其他代币)为你的代币进行背书,以便可以市场价自动化买卖代币,我们可以这么做。如果要使用浮动的价格,也可以在这里设置** @param newSellPrice 新的卖出价格* @param newBuyPrice 新的买入价格*/function setPrices(uint256 newSellPrice, uint256 newBuyPrice) onlyOwner {sellPrice = newSellPrice;buyPrice = newBuyPrice;}/**
* 使用以太币购买代币
*/
function buy() payable public {
uint amount = msg.value / buyPrice;

_transfer(this, msg.sender, amount);
}

/**
* @dev 卖出代币
* @return 要卖出的数量(单位是wei)
*/
function sell(uint256 amount) public {

//检查合约的余额是否充足
require(this.balance >= amount * sellPrice);

_transfer(msg.sender, this, amount);

msg.sender.transfer(amount * sellPrice);
}}
    参考之前的方法,在 
Mist
 中重新部署合约,贴完代码后,在右侧选择 
My Advanced Token
Initial Supply
 输入初始金额5000,
Token name
 输入我们的代币名称 
陌上花开A
Token symbol
 代币符号我们输入 
#
,然后点击部署,输入部署帐户的密码。    创建成功以后,我们在合约列表页,可以看到刚才创建的新合约
陌上花开A
    点击 
Mist
 上面的发送,我们先给帐户
0xd29adaadf3a40fd0b68c83c222c10d3ea637dce0
转入100个以太币。    操作成功以后,我们能够在钱包页面看到
Account 4
已经有了
100
以太币。  

7.6、使用以太币购买代币

  接下来,我们进入合约页面,使用以太币购买 
陌上花开A
 代币,进入合约界面后,我们能够看到代币上的以太币是 
0 ether
,在右侧选择 
Buy
 方法,
Execut from
 选择 
Account 4
,在 
Send ether
 输入 
10
 个以太币,点击 
执行
    执行成功以后,能够看到当前页面自动刷新,合约中已经有了
10 ether
,代币的总量不变    再次回到 
钱包
 页面,可以看到 
Account 4
 已经从 
100 ether
 变成了 
90 ether
,并且多了一个代币图标。    点击 
Account 4
 帐号进去,可以看到一些详细信息,ether的总量是 
89,999081514
而不是 
90
,是因为执行合约的时候,我们会消费一定的 
gas
。我们设置的费率是1:4,所以 
10 ether
,只可以购买 
2.5
 个 
陌上花开A
 代币,最小单位也是wei,所以是 
2,500000000000000000
  

7.7、卖出代币

  进入合约界面后,我们能够看到代币上的以太币是 
10 ether
,在右侧选择 
Sell
 方法,在 
Amount
 处输入 
2000000000000000000
(因为我们刚才购买了2.5个代币,现在卖出2个,卖出的最小单位是wei),
Execut from
 选择 
Account 4
,点击 
执行
    执行以后,在代币的详情页面,能够看到从 
10 ether
变成了 
6 ether
,因为刚才 
Account 4
 卖出了 
2
 个 
陌上花开A
 代币,而我们设置的卖价是 
1个代币
 能卖出 
2个以太币
    再次回到 
Account 4
 的详情页面,能够看到以太币变成了 
93,998273026
,而 
陌上花开A
 代币的数量,变成了 
0,500000000000000000
  

8、常见问题

8.1、在调试
Mist
的过程中,创建了很多个合约,如何删除?

  In the Ethereum Wallet (Mist) menu, click on Develop -> Toggle Developer Tools -> Wallet UI. Click on the Console tab
CustomContracts.find().fetch().map(
function(m) { CustomContracts.remove(m._id);}
)

                                            
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: