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.jsv7.x(use the prefered installation method for your OS)Meteor javascript app frameworkYarn package managerElectron
v1.7.9cross 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 gulpyarn其他平台的安装方法,可以参考: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个代币在里面,如下图:
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上方的
钱包中的主帐号这里看到有个小图标,说明主帐户已经有了代币,其他帐户是没有这个图标的
陌上花开币,点击
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 tabCustomContracts.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 实现众筹合约的实例
- 『孔壹学院』以太坊(Ethereum)代币系统、智能合约开发实战课程
- 以太坊笔记 使用 Browser-solidity 在 Go-Ethereum1.7.2 上进行简单的智能合约部署
- 以太坊智能合约实现代币空投
- struts2 结合extjs实现的一个登录实例
- 递归神经网络RNN原理——Elman网络原理——结合实例MATLAB(BPTT算法)实现
- 简单的实现JavaFX与OpenCV结合的实例
- java计划任务调度框架quartz结合spring实现调度的配置实例代码分享
- Ethereum 智能合约 testrpc+truffle 开发环境搭建
- java计划任务调度框架quartz结合spring实现调度的配置实例代码分享
- 以太坊智能合约虚拟机(EVM)原理与实现
- 智能指针实现代码--定时器实例
- php+xml结合Ajax实现点赞功能完整实例
- php结合ajax实现赞、顶、踩功能实例
- 以太坊智能合约代币应用开发(4)-web3客户端与geth节点交互
- 递归神经网络LSTM原理——结合实例MATLAB实现
- 开发智能合约的注意事项(以太坊-Ethereum)
- php+mysql结合Ajax实现点赞功能完整实例
- php结合ajax实现赞、顶、踩功能实例