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

2023-05-10,,

目录

目录
目录
1、什么是 Mist
2、Mist 在哪里下载?
3、Mist 有哪些依赖?
4、如何安装 Mist?
4.1、安装 Mist 依赖工具包
4.2、安装 Mist
4.3、启动 Mist,连接到 Geth
5、使用 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 framework
Yarn package manager
Electron v1.7.9 cross platform desktop app framework
Gulp 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,然后点击执行,在弹出的层中输入调用合约帐户的密码,确认操作。

我们能够看到实际调用合约的过程中,会花费一定的gasgas和以太币会根据区块的算力有一个计算公式,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 { //避免转帐的地址是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; //通知任何监听该交易的客户端
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 allowance allowance[_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、如何部署

  如上面的部署中,我们将完整的代码,贴到 Mistsolidity合约原始代码 处,在右侧选择 tokenInitial Supply 输入初始金额5000Token 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 的变量 ownermodifier 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 { //避免转帐的地址是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; //通知任何监听该交易的客户端
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 allowance allowance[_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 { //卖出的汇率,一个代币,可以卖出多少个以太币,单位是wei
uint256 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 { //避免转帐的地址是0x0
require (_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 TokenInitial Supply 输入初始金额5000,Token name 输入我们的代币名称 陌上花开AToken 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);}
)

博文作者:迦壹

博客地址:Go-Ethereum 1.7.2 结合 Mist 0.9.2 实现代币智能合约的实例

转载声明:可以转载, 但必须以超链接形式标明文章原始出处和作者信息及版权声明,谢谢合作!


Go-Ethereum 1.7.2 结合 Mist 0.9.2 实现代币智能合约的实例的相关教程结束。

《Go-Ethereum 1.7.2 结合 Mist 0.9.2 实现代币智能合约的实例.doc》

下载本文的Word格式文档,以方便收藏与打印。