代幣示例及講解

(注:本文是在原文的基礎(chǔ)上,根據(jù)個(gè)人的理解,修改部分內(nèi)容并添加了一些注釋)

買賣部分代碼未調(diào)試通過(guò)


基礎(chǔ)版的代幣合約

下面是一個(gè)最簡(jiǎn)單的代幣合約代碼,主要介紹可以看注釋:

pragma solidity 0.4.20;

/**

* @title 基礎(chǔ)版的代幣合約

*/

contract token {


? ? /* 公共變量 */

? ? string public standard = "https://mshk.top";


? ? /*記錄所有余額的映射*/

? ? mapping (address => uint256) public balanceOf;


? ? /* 初始化合約,并且把初始的所有代幣都給這合約的創(chuàng)建者

? ? * @param initialSupply 代幣的總數(shù)

? ? */

? ? function token (uint256 initialSupply) public {

? ? ? ? balanceOf[msg.sender] = initialSupply;

? ? }


? ? /**

? ? * 私有方法從一個(gè)帳戶發(fā)送給另一個(gè)帳戶代幣

? ? * @param? from address 發(fā)送代幣的地址

? ? * @param? to address 接受代幣的地址

? ? * @param? value uint256 接受代幣的數(shù)量

? ? */

? ? function _transfer (address from, address to, uint256 value) internal {


? ? ? ? //避免轉(zhuǎn)帳的地址是0x0

? ? ? ? require(to != 0x0);


? ? ? ? //檢查發(fā)送者是否擁有足夠余額

? ? ? ? require(balanceOf[from] >= value);


? ? ? ? //檢查是否溢出

? ? ? ? require(balanceOf[to] + value > balanceOf[to]);


? ? ? ? //保存數(shù)據(jù)用于后面的判斷

? ? ? ? uint previousBalances = balanceOf[from] + balanceOf[to];


? ? ? ? //從發(fā)送者減掉發(fā)送額

? ? ? ? balanceOf[from] -= value;


? ? ? ? //給接收者加上相同的量

? ? ? ? balanceOf[to] += value;


? ? ? ? //判斷買、賣雙方的數(shù)據(jù)是否和轉(zhuǎn)換前一致

? ? ? ? assert(balanceOf[from] + balanceOf[to] == previousBalances);

? ? }


? ? /**

? ? * 從主帳戶合約調(diào)用者發(fā)送給別人代幣

? ? * @param? to address 接受代幣的地址

? ? * @param? value uint256 接受代幣的數(shù)量

? ? */

? ? function transfer (address to, uint256 value) public {

? ? ? ? _transfer(msg.sender, to, value);

? ? }

}

接下來(lái)我們將上面的合約代碼,通過(guò)Mist部署到我們的私有鏈

首先如下圖中,點(diǎn)擊合約->部署新合約:

然后如下面的兩張圖,選擇創(chuàng)建合約的帳戶,將上面的代碼貼到SOLIDITY合約原始代碼處,在右側(cè)選擇要部署的合約token,在token的下面Initial Supply處,輸入我們要初始化的金額5000用于獎(jiǎng)勵(lì)合約創(chuàng)建者,然后在頁(yè)面的最下面,點(diǎn)擊部署,的彈出的層中,輸入創(chuàng)建合約這個(gè)帳號(hào)的密碼,輸入正確以后,合約創(chuàng)建成功。

創(chuàng)建一個(gè)合約以后,再點(diǎn)擊Mist右側(cè)的合約,然后在定制化合約的下面,可以看到我們剛剛創(chuàng)建的合約TOKEN,如下圖:

注意,在合約下面也有一串0x開(kāi)頭的地址,這個(gè)就相當(dāng)于一個(gè)錢包的地址。在以太坊中,合約也相當(dāng)于一個(gè)帳戶。

點(diǎn)擊TOKEN,進(jìn)入到合約里。在下面的Balance Of處,輸入剛才創(chuàng)建合約帳戶的地址0xa18e688326ab13b6147ce3ca2213db143a4ec2ee,可以看到是有5000個(gè)代幣在里面,如下圖:

在代幣創(chuàng)建的時(shí)候,初始值我們?cè)O(shè)置的是5000,所以只有創(chuàng)建帳戶的地址有代幣,而輸入其他帳戶的地址,如0xc81896af13449a82f22699311df4ec4b48c07718,是沒(méi)有值的。

接下來(lái),我們向0xc81896af13449a82f22699311df4ec4b48c07718這個(gè)帳戶地址,轉(zhuǎn)入一些代幣。點(diǎn)擊右側(cè)選擇函數(shù)->選擇Transfer,在_to中輸入0xc81896af13449a82f22699311df4ec4b48c07718,在_value中輸入500,然后點(diǎn)擊執(zhí)行,在彈出的層中輸入調(diào)用合約帳戶的密碼,確認(rèn)操作。

我們能夠看到實(shí)際調(diào)用合約的過(guò)程中,會(huì)花費(fèi)一定的gas,gas和以太幣會(huì)根據(jù)區(qū)塊的算力有一個(gè)計(jì)算公式,gas一般用于獎(jiǎng)勵(lì)給挖礦者。

在transfer方法中,我們?cè)O(shè)定了,只有合約的調(diào)用者msg.sender才能向指定地址轉(zhuǎn)移代幣。

/** * 從主帳戶合約調(diào)用者發(fā)送給別人代幣 *@param_to address 接受代幣的地址 *@param_value uint256 接受代幣的數(shù)量 */functiontransfer(address _to, uint256 _value)public{? ? _transfer(msg.sender, _to, _value);}

這時(shí),再次進(jìn)入合約,在Balance Of處,輸入兩個(gè)帳戶的地址,可以看到,余額都發(fā)生的變化,如下圖:

改善代幣

通過(guò)上面的操作,我們已經(jīng)可以將合約代碼,通過(guò) Mist 部署到我們創(chuàng)建的私有鏈中,同樣如果部署到生產(chǎn)環(huán)境,只需要連上以太坊的網(wǎng)絡(luò),同樣的方法也可以將你的合約,部署到生產(chǎn)環(huán)境中,不過(guò)要根據(jù)代碼的大小,花費(fèi)一些以太幣。

實(shí)際使用過(guò)程中,交易的過(guò)程,需要通知到客戶端,并且記錄到區(qū)塊中,我們可以使用event事件來(lái)指定,如下代碼進(jìn)行聲明:

//在區(qū)塊鏈上創(chuàng)建一個(gè)事件,用以通知客戶端eventTransfer(address indexed from, address indexed to, uint256 value);

設(shè)置一些代幣的基本信息

/* 公共變量 */stringpublicstandard ='https://mshk.top';stringpublicname;//代幣名稱stringpublicsymbol;//代幣符號(hào)比如'$'uint8publicdecimals =18;//代幣單位,展示的小數(shù)點(diǎn)后面多少個(gè)0,和以太幣一樣后面是是18個(gè)0uint256publictotalSupply;//代幣總量

某些特定的場(chǎng)景中,不允許某個(gè)帳戶花費(fèi)超過(guò)指定的上限,避免大額支出,我們可以添加一個(gè)approve方法,來(lái)設(shè)置一個(gè)允許支出最大金額的列表。

注:根據(jù)個(gè)人的理解,approve是其他合約調(diào)用此合約,或者是代理,例如交易所,使用你的賬戶時(shí),你可以設(shè)置一個(gè)代幣數(shù)量。他們只能對(duì)你設(shè)置的數(shù)量的代幣進(jìn)行操作,不知道這樣理解是否準(zhǔn)確。下面是一個(gè)對(duì)approve、allowance,以及后面的transferFrom的解釋:

注:approve、transferFrom及allowance解釋:

賬戶A有1000個(gè)ETH,想允許B賬戶隨意調(diào)用100個(gè)ETH。A賬戶按照以下形式調(diào)用approve函數(shù)approve(B,100)。當(dāng)B賬戶想用這100個(gè)ETH中的10個(gè)ETH給C賬戶時(shí),則調(diào)用transferFrom(A, C, 10)。這時(shí)調(diào)用allowance[A][B]可以查看B賬戶還能夠調(diào)用A賬戶多少個(gè)token。

mapping (address => mapping (address => uint256))publicallowance;/** * 設(shè)置帳戶允許支付的最大金額 * * 一般在智能合約的時(shí)候,避免支付過(guò)多,造成風(fēng)險(xiǎn) * *@param_spender 帳戶地址 *@param_value 金額 */functionapprove(address _spender, uint256 _value)publicreturns(bool success){? ? allowance[msg.sender][_spender] = _value;returntrue;}

同樣在solidity中,合約之間也可以相互調(diào)用,我們可以增加一個(gè)approveAndCall方法,用于在設(shè)置帳戶最大支出金額后,可以做一些其他操作。

interfacetokenRecipient{functionreceiveApproval(address _from, uint256 _value, address _token, bytes _extraData)public; }/** * 設(shè)置帳戶允許支付的最大金額 * * 一般在智能合約的時(shí)候,避免支付過(guò)多,造成風(fēng)險(xiǎn) * *@param_spender 帳戶地址 *@param_value 金額 */functionapprove(address _spender, uint256 _value)publicreturns(bool success){? ? allowance[msg.sender][_spender] = _value;returntrue;}/** * 設(shè)置帳戶允許支付的最大金額 * * 一般在智能合約的時(shí)候,避免支付過(guò)多,造成風(fēng)險(xiǎn),加入時(shí)間參數(shù),可以在 tokenRecipient 中做其他操作 * *@param_spender 帳戶地址 *@param_value 金額 *@param_extraData 操作的時(shí)間 */functionapproveAndCall(address _spender, uint256 _value, bytes _extraData)publicreturns(bool success){? ? tokenRecipient spender = tokenRecipient(_spender);if(approve(_spender, _value)) {? ? ? ? spender.receiveApproval(msg.sender, _value, this, _extraData);returntrue;? ? }}

我們可以增加一個(gè)burn方法,用于管理員減去指定帳戶的指定金額。進(jìn)行該方法操作時(shí),通知客戶端記錄到區(qū)塊鏈中。

注:代碼并沒(méi)有判斷調(diào)用者是否為管理員。

注:代理B在調(diào)用burnFrom刪除A賬戶余額時(shí),也需要?jiǎng)h除A授權(quán)給自己的可調(diào)用余額數(shù)。

//減去用戶余額事件event Burn(address indexed from, uint256 value);/** * 減少代幣調(diào)用者的余額 * * 操作以后是不可逆的 * *@param_value 要?jiǎng)h除的數(shù)量 */functionburn(uint256 _value)publicreturns(bool success){//檢查帳戶余額是否大于要減去的值require(balanceOf[msg.sender] >= _value);// Check if the sender has enough//給指定帳戶減去余額balanceOf[msg.sender] -= _value;//代幣問(wèn)題做相應(yīng)扣除totalSupply -= _value;? ? Burn(msg.sender, _value);returntrue;}/** * 刪除帳戶的余額(含其他帳戶) * * 刪除以后是不可逆的 * *@param_from 要操作的帳戶地址 *@param_value 要減去的數(shù)量 */functionburnFrom(address _from, uint256 _value)publicreturns(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);returntrue;}

完整的代碼如下:

pragma solidity0.4.20;interfacetokenRecipient{functionreceiveApproval(address _from, uint256 _value, address _token, bytes _extraData)external; }/** *@title基礎(chǔ)版的代幣合約 */contract token {/* 公共變量 */stringpublicstandard ='https://mshk.top';? ? stringpublicname;//代幣名稱stringpublicsymbol;//代幣符號(hào)比如'$'uint8publicdecimals =18;//代幣單位,展示的小數(shù)點(diǎn)后面多少個(gè)0,和以太幣一樣后面是是18個(gè)0uint256publictotalSupply;//代幣總量/*記錄所有余額的映射*/mapping (address => uint256)publicbalanceOf;? ? mapping (address => mapping (address => uint256))publicallowance;/* 在區(qū)塊鏈上創(chuàng)建一個(gè)事件,用以通知客戶端*/event Transfer(address indexed from, address indexed to, uint256 value);//轉(zhuǎn)帳通知事件event Burn(address indexed from, uint256 value);//減去用戶余額事件/* 初始化合約,并且把初始的所有代幣都給這合約的創(chuàng)建者? ? *@paraminitialSupply 代幣的總數(shù)? ? *@paramtokenName 代幣名稱? ? *@paramtokenSymbol 代幣符號(hào)? ? */functiontoken(uint256 initialSupply, string tokenName, string tokenSymbol)public{//初始化總量totalSupply = initialSupply *10** uint256(decimals);//以太幣是10^18,后面18個(gè)0,所以默認(rèn)decimals是18//給指定帳戶初始化代幣總量,初始化用于獎(jiǎng)勵(lì)合約創(chuàng)建者balanceOf[msg.sender] = totalSupply;? ? ? ? name = tokenName;? ? ? ? symbol = tokenSymbol;? ? }/**? ? * 私有方法從一個(gè)帳戶發(fā)送給另一個(gè)帳戶代幣? ? *@param_from address 發(fā)送代幣的地址? ? *@param_to address 接受代幣的地址? ? *@param_value uint256 接受代幣的數(shù)量? ? */function_transfer(address _from, address _to, uint256 _value)internal{//避免轉(zhuǎn)帳的地址是0x0require(_to !=0x0);//檢查發(fā)送者是否擁有足夠余額require(balanceOf[_from] >= _value);//檢查是否溢出require(balanceOf[_to] + _value > balanceOf[_to]);//保存數(shù)據(jù)用于后面的判斷uint previousBalances = balanceOf[_from] + balanceOf[_to];//從發(fā)送者減掉發(fā)送額balanceOf[_from] -= _value;//給接收者加上相同的量balanceOf[_to] += _value;//通知任何監(jiān)聽(tīng)該交易的客戶端Transfer(_from, _to, _value);//判斷買、賣雙方的數(shù)據(jù)是否和轉(zhuǎn)換前一致assert(balanceOf[_from] + balanceOf[_to] == previousBalances);? ? }/**? ? * 從主帳戶合約調(diào)用者發(fā)送給別人代幣? ? *@param_to address 接受代幣的地址? ? *@param_value uint256 接受代幣的數(shù)量? ? */functiontransfer(address _to, uint256 _value)public{? ? ? ? _transfer(msg.sender, _to, _value);? ? }/**? ? * 從某個(gè)指定的帳戶中,向另一個(gè)帳戶發(fā)送代幣? ? *? ? * 調(diào)用過(guò)程,會(huì)檢查設(shè)置的允許最大交易額? ? *? ? *@param_from address 發(fā)送者地址? ? *@param_to address 接受者地址? ? *@param_value uint256 要轉(zhuǎn)移的代幣數(shù)量? ? *@returnsuccess? ? ? ? 是否交易成功? ? */functiontransferFrom(address _from, address _to, uint256 _value)publicreturns(bool success){//檢查發(fā)送者是否擁有足夠余額require(_value <= allowance[_from][msg.sender]);// Check allowanceallowance[_from][msg.sender] -= _value;? ? ? ? _transfer(_from, _to, _value);returntrue;? ? }/**? ? * 設(shè)置帳戶允許支付的最大金額? ? *? ? * 一般在智能合約的時(shí)候,避免支付過(guò)多,造成風(fēng)險(xiǎn)? ? *? ? *@param_spender 帳戶地址? ? *@param_value 金額? ? */functionapprove(address _spender, uint256 _value)publicreturns(bool success){? ? ? ? allowance[msg.sender][_spender] = _value;returntrue;? ? }/**? ? * 設(shè)置帳戶允許支付的最大金額? ? *? ? * 一般在智能合約的時(shí)候,避免支付過(guò)多,造成風(fēng)險(xiǎn),加入時(shí)間參數(shù),可以在 tokenRecipient 中做其他操作? ? *? ? *@param_spender 帳戶地址? ? *@param_value 金額? ? *@param_extraData 操作的時(shí)間? ? */functionapproveAndCall(address _spender, uint256 _value, bytes _extraData)publicreturns(bool success){? ? ? ? tokenRecipient spender = tokenRecipient(_spender);if(approve(_spender, _value)) {? ? ? ? ? ? spender.receiveApproval(msg.sender, _value, this, _extraData);returntrue;? ? ? ? }? ? }/**? ? * 減少代幣調(diào)用者的余額? ? *? ? * 操作以后是不可逆的? ? *? ? *@param_value 要?jiǎng)h除的數(shù)量? ? */functionburn(uint256 _value)publicreturns(bool success){//檢查帳戶余額是否大于要減去的值require(balanceOf[msg.sender] >= _value);// Check if the sender has enough//給指定帳戶減去余額balanceOf[msg.sender] -= _value;//代幣問(wèn)題做相應(yīng)扣除totalSupply -= _value;? ? ? ? Burn(msg.sender, _value);returntrue;? ? }/**? ? * 刪除帳戶的余額(含其他帳戶)? ? *? ? * 刪除以后是不可逆的? ? *? ? *@param_from 要操作的帳戶地址? ? *@param_value 要減去的數(shù)量? ? */functionburnFrom(address _from, uint256 _value)publicreturns(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);returntrue;? ? }}

如上面的部署中,我們將完整的代碼,貼到Mist的solidity合約原始代碼處,在右側(cè)選擇token,Initial Supply輸入初始金額5000,Token name輸入我們的代幣名稱陌上花開(kāi),Token symbol代幣符號(hào)我們輸入$$,然后點(diǎn)擊部署,輸入部署帳戶的密碼。

部署合約以后,我們能夠在合約頁(yè)面看到剛才創(chuàng)建的合約。

點(diǎn)擊合約名稱,可以看到合約的一些基本信息,以及合約和操作函數(shù)

我們能夠在Mist上方的錢包中的主帳號(hào)這里看到有個(gè)小圖標(biāo),說(shuō)明主帳戶已經(jīng)有了代幣,其他帳戶是沒(méi)有這個(gè)圖標(biāo)的

點(diǎn)擊進(jìn)入主帳號(hào)以后,我們就可以看到主帳戶已經(jīng)擁有的代幣和以太幣的數(shù)量,因?yàn)槲覀兪菂⒖家蕴珟胚M(jìn)行設(shè)置,最小單位是wei,所以小數(shù)點(diǎn)后面有18個(gè)0。

接下來(lái),我們向另一個(gè)帳戶發(fā)送一些陌上花開(kāi)幣,點(diǎn)擊Mist上方的發(fā)送,輸入發(fā)送的帳戶地址,輸入數(shù)量500,選擇發(fā)送的是陌上花開(kāi)幣,點(diǎn)擊發(fā)送,如下圖

再次回到錢包中,我們可以看到,另一個(gè)帳戶也有了一個(gè)代幣的圖標(biāo),說(shuō)明代幣已經(jīng)轉(zhuǎn)入成功。

現(xiàn)在你擁有了自己的代幣,也可以做轉(zhuǎn)入轉(zhuǎn)出操作。可以被用于價(jià)值交換,或者工作時(shí)間追蹤或者其他項(xiàng)目。

高級(jí)版的代幣功能

雖然區(qū)塊鏈?zhǔn)侨ブ行幕模菍?shí)現(xiàn)對(duì)代幣(合約)的管理,也在許多應(yīng)用中有需求,為了對(duì)代幣進(jìn)行管理,首先需要給合約添加一個(gè)管理者。

** * owned 是一個(gè)管理者 */contract owned {? ? addresspublicowner;/**

? ? * 初臺(tái)化構(gòu)造函數(shù)

? ? */functionowned(){? ? ? ? owner = msg.sender;? ? }/**

? ? * 判斷當(dāng)前合約調(diào)用者是否是管理員

? ? */modifier onlyOwner {require(msg.sender == owner);? ? ? ? _;? ? }/**? ? * 指派一個(gè)新的管理員? ? *@paramnewOwner address 新的管理員帳戶地址? ? */functiontransferOwnership(address newOwner)onlyOwner{if(newOwner != address(0)) {? ? ? ? owner = newOwner;? ? ? }? ? }}

上面的代碼是一個(gè)非常簡(jiǎn)單的合約,我們可以在后面的代碼中,使用繼承來(lái)實(shí)現(xiàn)后續(xù)的功能。

/** *@title高級(jí)版代幣 * 增加凍結(jié)用戶、挖礦、根據(jù)指定匯率購(gòu)買(售出)代幣價(jià)格的功能 */contract MyAdvancedToken is owned{}

在MyAdvancedToken的所有方法中,可以使用owned的變量owner和modifier onlyOwner。

去中心化的管理者

我們也可以在構(gòu)造函數(shù)中設(shè)置是否需要一個(gè)去中心化的管理者。

/*初始化合約,并且把初始的所有的令牌都給這合約的創(chuàng)建者 *@paraminitialSupply 所有幣的總數(shù) *@paramtokenName 代幣名稱 *@paramtokenSymbol 代幣符號(hào) *@paramcentralMinter 是否指定其他帳戶為合約所有者,為0是去中心化 */functionMyAdvancedToken(

? uint256 initialSupply,

? string tokenName,

? string tokenSymbol,

? address centralMinter

){//設(shè)置合約的管理者if(centralMinter !=0) owner = centralMinter;}

代幣增發(fā)

實(shí)現(xiàn)代幣增發(fā),代幣增發(fā)就如同央行印鈔票一樣,想必很多人都需要這樣的功能。

/** * 合約擁有者,可以為指定帳戶創(chuàng)造一些代幣 *@paramtarget address 帳戶地址 *@parammintedAmount uint256 增加的金額(單位是wei) */functionmintToken(address target, uint256 mintedAmount)onlyOwner{//給指定地址增加代幣,同時(shí)總量也相加balanceOf[target] += mintedAmount;? ? totalSupply += mintedAmount;}

在方法的最后有一個(gè)onlyOwner,說(shuō)明mintToken是繼承了onlyOwner方法,會(huì)先調(diào)用modifier onlyOwner方法,然后將mintToken方法的內(nèi)容,插入到下劃線 _ 處調(diào)用。

凍結(jié)資產(chǎn)

有的場(chǎng)景中,某些用戶違反了規(guī)定,需要凍結(jié)/解凍帳戶,不想讓他使用已經(jīng)擁有的代幣.可以增加以下代碼來(lái)控制:

//是否凍結(jié)帳戶的列表mapping (address => bool)publicfrozenAccount;//定義一個(gè)事件,當(dāng)有資產(chǎn)被凍結(jié)的時(shí)候,通知正在監(jiān)聽(tīng)事件的客戶端event FrozenFunds(address target, bool frozen);/** * 增加凍結(jié)帳戶名稱 * * 你可能需要監(jiān)管功能以便你能控制誰(shuí)可以/誰(shuí)不可以使用你創(chuàng)建的代幣合約 * *@paramtarget address 帳戶地址 *@paramfreeze bool? ? 是否凍結(jié) */functionfreezeAccount(address target, bool freeze)onlyOwner{? ? frozenAccount[target] = freeze;? ? FrozenFunds(target, freeze);}

代幣買賣(兌換)

可以自己的貨幣中實(shí)現(xiàn)代幣與其他數(shù)字貨幣(ether 或其他tokens)的兌換機(jī)制。有了這個(gè)功能,我們的合約就可以在一買一賣中賺利潤(rùn)了。

//賣出的匯率,一個(gè)代幣,可以賣出多少個(gè)以太幣,單位是weiuint256publicsellPrice;//買入的匯率,1個(gè)以太幣,可以買幾個(gè)代幣uint256publicbuyPrice;/** * 設(shè)置買賣價(jià)格 * * 如果你想讓ether(或其他代幣)為你的代幣進(jìn)行背書(shū),以便可以市場(chǎng)價(jià)自動(dòng)化買賣代幣,我們可以這么做。如果要使用浮動(dòng)的價(jià)格,也可以在這里設(shè)置 * *@paramnewSellPrice 新的賣出價(jià)格 *@paramnewBuyPrice 新的買入價(jià)格 */functionsetPrices(uint256 newSellPrice, uint256 newBuyPrice)onlyOwner{? ? sellPrice = newSellPrice;? ? buyPrice = newBuyPrice;}

然后增加買、賣的方法,每一次的交易,都會(huì)消耗掉一定的ether。在 Solidity 0.4.0 之后,要接收ether的函數(shù)都要加一個(gè)payable屬性,如果你開(kāi)放的合約,需要?jiǎng)e人轉(zhuǎn)錢給你,就需要加payable。

下面的方法,不會(huì)增加代幣,只是改變調(diào)用合約者的代幣數(shù)量,買、賣的價(jià)格單位不是ether,而是wei,這是以太幣中最小的單位(就像美元里的美分,比特幣里的聰)。1 ether = 1000000000000000000 wei。因此使用ether設(shè)置價(jià)格的時(shí)候,在最后加18個(gè)0。

當(dāng)創(chuàng)建合約的時(shí)候,發(fā)送足夠多的ether作為代幣的背書(shū),否則你的合約就是破產(chǎn)的,你的用戶就不能夠賣掉他們的代幣。

/**

* 使用以太幣購(gòu)買代幣

*/functionbuy()payablepublic{? uint amount = msg.value / buyPrice;? _transfer(this, msg.sender, amount);}/**

* @dev 賣出代幣

* @return 要賣出的數(shù)量(單位是wei)

*/functionsell(uint256 amount)public{//檢查合約的余額是否充足require(this.balance >= amount * sellPrice);? ? _transfer(msg.sender,this, amount);? ? msg.sender.transfer(amount * sellPrice);}

實(shí)現(xiàn)Gas的自動(dòng)補(bǔ)充

以太坊中的交易時(shí)需要gas(支付給礦工的費(fèi)用,費(fèi)用以ether來(lái)支付)。而如果用戶沒(méi)有以太幣,只有代幣的情況(或者我們想向用戶隱藏以太坊的細(xì)節(jié)),就需要自動(dòng)補(bǔ)充gas的功能。這個(gè)功能將使我們代幣更加好用。

自動(dòng)補(bǔ)充的邏輯是這樣了,在執(zhí)行交易之前,我們判斷用戶的余額(用來(lái)支付礦工的費(fèi)用),如果用戶的余額非常少(低于某個(gè)閾值時(shí))可能影響到交易進(jìn)行,合約自動(dòng)售出一部分代幣來(lái)補(bǔ)充余額,以幫助用戶順利完成交易。

先來(lái)設(shè)定余額閾值:

uint minBalanceForAccounts;functionsetMinBalance(uint minimumBalanceInFinney)onlyOwner{? ? ? ? minBalanceForAccounts = minimumBalanceInFinney *1finney;? ? }

finney 是貨幣單位 1 finney = 0.001eth

然后交易中加入對(duì)用戶的余額的判斷。

functiontransfer(address _to, uint256 _value){? ? ...if(msg.sender.balance < minBalanceForAccounts)? ? ? ? sell((minBalanceForAccounts - msg.sender.balance) / sellPrice);if(_to.balance

全部代碼

pragma solidity0.4.20;interfacetokenRecipient{functionreceiveApproval(address _from, uint256 _value, address _token, bytes _extraData)external; }/**

* owned 是一個(gè)管理者

*/contract owned {? ? addresspublicowner;/**

? ? * 初臺(tái)化構(gòu)造函數(shù)

? ? */functionowned()public{? ? ? ? owner = msg.sender;? ? }/**

? ? * 判斷當(dāng)前合約調(diào)用者是否是管理員

? ? */modifier onlyOwner {require(msg.sender == owner);? ? ? ? _;? ? }/**? ? * 指派一個(gè)新的管理員? ? *@paramnewOwner address 新的管理員帳戶地址? ? */functiontransferOwnership(address newOwner)onlyOwnerpublic{if(newOwner != address(0)) {? ? ? ? owner = newOwner;? ? ? }? ? }}/** *@title基礎(chǔ)版的代幣合約 */contract token {/* 公共變量 */stringpublicstandard ='https://mshk.top';? ? stringpublicname;//代幣名稱stringpublicsymbol;//代幣符號(hào)比如'$'uint8publicdecimals =18;//代幣單位,展示的小數(shù)點(diǎn)后面多少個(gè)0,和以太幣一樣后面是是18個(gè)0uint256publictotalSupply;//代幣總量/*記錄所有余額的映射*/mapping (address => uint256)publicbalanceOf;? ? mapping (address => mapping (address => uint256))publicallowance;/* 在區(qū)塊鏈上創(chuàng)建一個(gè)事件,用以通知客戶端*/event Transfer(address indexed from, address indexed to, uint256 value);//轉(zhuǎn)帳通知事件event Burn(address indexed from, uint256 value);//減去用戶余額事件/* 初始化合約,并且把初始的所有代幣都給這合約的創(chuàng)建者? ? *@paraminitialSupply 代幣的總數(shù)? ? *@paramtokenName 代幣名稱? ? *@paramtokenSymbol 代幣符號(hào)? ? */functiontoken(uint256 initialSupply, string tokenName, string tokenSymbol)public{//初始化總量totalSupply = initialSupply *10** uint256(decimals);//以太幣是10^18,后面18個(gè)0,所以默認(rèn)decimals是18//給指定帳戶初始化代幣總量,初始化用于獎(jiǎng)勵(lì)合約創(chuàng)建者//balanceOf[msg.sender] = totalSupply;balanceOf[this] = totalSupply;? ? ? ? name = tokenName;? ? ? ? symbol = tokenSymbol;? ? }/**? ? * 私有方法從一個(gè)帳戶發(fā)送給另一個(gè)帳戶代幣? ? *@param_from address 發(fā)送代幣的地址? ? *@param_to address 接受代幣的地址? ? *@param_value uint256 接受代幣的數(shù)量? ? */function_transfer(address _from, address _to, uint256 _value)internal{//避免轉(zhuǎn)帳的地址是0x0require(_to !=0x0);//檢查發(fā)送者是否擁有足夠余額require(balanceOf[_from] >= _value);//檢查是否溢出require(balanceOf[_to] + _value > balanceOf[_to]);//保存數(shù)據(jù)用于后面的判斷uint previousBalances = balanceOf[_from] + balanceOf[_to];//從發(fā)送者減掉發(fā)送額balanceOf[_from] -= _value;//給接收者加上相同的量balanceOf[_to] += _value;//通知任何監(jiān)聽(tīng)該交易的客戶端Transfer(_from, _to, _value);//判斷買、賣雙方的數(shù)據(jù)是否和轉(zhuǎn)換前一致assert(balanceOf[_from] + balanceOf[_to] == previousBalances);? ? }/**? ? * 從主帳戶合約調(diào)用者發(fā)送給別人代幣? ? *@param_to address 接受代幣的地址? ? *@param_value uint256 接受代幣的數(shù)量? ? */functiontransfer(address _to, uint256 _value)public{? ? ? ? _transfer(msg.sender, _to, _value);? ? }/**? ? * 從某個(gè)指定的帳戶中,向另一個(gè)帳戶發(fā)送代幣? ? *? ? * 調(diào)用過(guò)程,會(huì)檢查設(shè)置的允許最大交易額? ? *? ? *@param_from address 發(fā)送者地址? ? *@param_to address 接受者地址? ? *@param_value uint256 要轉(zhuǎn)移的代幣數(shù)量? ? *@returnsuccess? ? ? ? 是否交易成功? ? */functiontransferFrom(address _from, address _to, uint256 _value)publicreturns(bool success){//檢查發(fā)送者是否擁有足夠余額require(_value <= allowance[_from][msg.sender]);// Check allowanceallowance[_from][msg.sender] -= _value;? ? ? ? _transfer(_from, _to, _value);returntrue;? ? }/**? ? * 設(shè)置帳戶允許支付的最大金額? ? *? ? * 一般在智能合約的時(shí)候,避免支付過(guò)多,造成風(fēng)險(xiǎn)? ? *? ? *@param_spender 帳戶地址? ? *@param_value 金額? ? */functionapprove(address _spender, uint256 _value)publicreturns(bool success){? ? ? ? allowance[msg.sender][_spender] = _value;returntrue;? ? }/**? ? * 設(shè)置帳戶允許支付的最大金額? ? *? ? * 一般在智能合約的時(shí)候,避免支付過(guò)多,造成風(fēng)險(xiǎn),加入時(shí)間參數(shù),可以在 tokenRecipient 中做其他操作? ? *? ? *@param_spender 帳戶地址? ? *@param_value 金額? ? *@param_extraData 操作的時(shí)間? ? */functionapproveAndCall(address _spender, uint256 _value, bytes _extraData)publicreturns(bool success){? ? ? ? tokenRecipient spender = tokenRecipient(_spender);if(approve(_spender, _value)) {? ? ? ? ? ? spender.receiveApproval(msg.sender, _value, this, _extraData);returntrue;? ? ? ? }? ? }/**? ? * 減少代幣調(diào)用者的余額? ? *? ? * 操作以后是不可逆的? ? *? ? *@param_value 要?jiǎng)h除的數(shù)量? ? */functionburn(uint256 _value)publicreturns(bool success){//檢查帳戶余額是否大于要減去的值require(balanceOf[msg.sender] >= _value);// Check if the sender has enough//給指定帳戶減去余額balanceOf[msg.sender] -= _value;//代幣問(wèn)題做相應(yīng)扣除totalSupply -= _value;? ? ? ? Burn(msg.sender, _value);returntrue;? ? }/**? ? * 刪除帳戶的余額(含其他帳戶)? ? *? ? * 刪除以后是不可逆的? ? *? ? *@param_from 要操作的帳戶地址? ? *@param_value 要減去的數(shù)量? ? */functionburnFrom(address _from, uint256 _value)publicreturns(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);returntrue;? ? }/**

? ? * 匿名方法,預(yù)防有人向這合約發(fā)送以太幣

? ? *//*function() {

? ? ? ? //return;? ? // Prevents accidental sending of ether

? ? }*/}/** *@title高級(jí)版代幣 * 增加凍結(jié)用戶、挖礦、根據(jù)指定匯率購(gòu)買(售出)代幣價(jià)格的功能 */contract MyAdvancedToken is owned, token {//賣出的匯率,一個(gè)代幣,可以賣出多少個(gè)以太幣,單位是weiuint256publicsellPrice;//買入的匯率,1個(gè)以太幣,可以買幾個(gè)代幣uint256publicbuyPrice;//是否凍結(jié)帳戶的列表mapping (address => bool)publicfrozenAccount;//定義一個(gè)事件,當(dāng)有資產(chǎn)被凍結(jié)的時(shí)候,通知正在監(jiān)聽(tīng)事件的客戶端event FrozenFunds(address target, bool frozen);/*初始化合約,并且把初始的所有的令牌都給這合約的創(chuàng)建者? ? *@paraminitialSupply 所有幣的總數(shù)? ? *@paramtokenName 代幣名稱? ? *@paramtokenSymbol 代幣符號(hào)? ? *@paramcentralMinter 是否指定其他帳戶為合約所有者,為0是去中心化? ? */functionMyAdvancedToken(

? ? ? uint256 initialSupply,

? ? ? string tokenName,

? ? ? string tokenSymbol,

? ? ? address centralMinter

? ? )token(initialSupply, tokenName, tokenSymbol)public{//設(shè)置合約的管理者if(centralMinter !=0) owner = centralMinter;? ? ? ? sellPrice =2;//設(shè)置1個(gè)單位的代幣(單位是wei),能夠賣出2個(gè)以太幣buyPrice =4;//設(shè)置1個(gè)以太幣,可以買0.25個(gè)代幣}/**? ? * 私有方法,從指定帳戶轉(zhuǎn)出余額? ? *@param_from address 發(fā)送代幣的地址? ? *@param_to address 接受代幣的地址? ? *@param_value uint256 接受代幣的數(shù)量? ? */function_transfer(address _from, address _to, uint _value)internal{//避免轉(zhuǎn)帳的地址是0x0require(_to !=0x0);//檢查發(fā)送者是否擁有足夠余額require(balanceOf[_from] > _value);//檢查是否溢出require(balanceOf[_to] + _value > balanceOf[_to]);//檢查 凍結(jié)帳戶require(!frozenAccount[_from]);require(!frozenAccount[_to]);//從發(fā)送者減掉發(fā)送額balanceOf[_from] -= _value;//給接收者加上相同的量balanceOf[_to] += _value;//通知任何監(jiān)聽(tīng)該交易的客戶端Transfer(_from, _to, _value);? ? }/**? ? * 合約擁有者,可以為指定帳戶創(chuàng)造一些代幣? ? *@paramtarget address 帳戶地址? ? *@parammintedAmount uint256 增加的金額(單位是wei)? ? */functionmintToken(address target, uint256 mintedAmount)onlyOwnerpublic{//給指定地址增加代幣,同時(shí)總量也相加balanceOf[target] += mintedAmount;? ? ? ? totalSupply += mintedAmount;? ? ? ? Transfer(0, this, mintedAmount);? ? ? ? Transfer(this, target, mintedAmount);? ? }/**? ? * 增加凍結(jié)帳戶名稱? ? *? ? * 你可能需要監(jiān)管功能以便你能控制誰(shuí)可以/誰(shuí)不可以使用你創(chuàng)建的代幣合約? ? *? ? *@paramtarget address 帳戶地址? ? *@paramfreeze bool? ? 是否凍結(jié)? ? */functionfreezeAccount(address target, bool freeze)onlyOwnerpublic{? ? ? ? frozenAccount[target] = freeze;? ? ? ? FrozenFunds(target, freeze);? ? }/**? ? * 設(shè)置買賣價(jià)格? ? *? ? * 如果你想讓ether(或其他代幣)為你的代幣進(jìn)行背書(shū),以便可以市場(chǎng)價(jià)自動(dòng)化買賣代幣,我們可以這么做。如果要使用浮動(dòng)的價(jià)格,也可以在這里設(shè)置? ? *? ? *@paramnewSellPrice 新的賣出價(jià)格? ? *@paramnewBuyPrice 新的買入價(jià)格? ? */functionsetPrices(uint256 newSellPrice, uint256 newBuyPrice)onlyOwnerpublic{? ? ? ? sellPrice = newSellPrice;? ? ? ? buyPrice = newBuyPrice;? ? }/**

? ? * 使用以太幣購(gòu)買代幣

? ? */functionbuy()payablepublic{? ? ? uint amount = msg.value / buyPrice;? ? ? _transfer(this, msg.sender, amount);? ? }/**? ? *@dev賣出代幣? ? *@return要賣出的數(shù)量(單位是wei)? ? */functionsell(uint256 amount)public{//檢查合約的余額是否充足require(this.balance >= amount * sellPrice);? ? ? ? _transfer(msg.sender, this, amount);? ? ? ? msg.sender.transfer(amount * sellPrice);? ? }}

參考之前的方法,在Mist中重新部署合約,貼完代碼后,在右側(cè)選擇My Advanced Token,Initial Supply輸入初始金額5000,Token name輸入我們的代幣名稱陌上花開(kāi)A,Token symbol代幣符號(hào)我們輸入#,然后點(diǎn)擊部署,輸入部署帳戶的密碼。

創(chuàng)建成功以后,我們?cè)诤霞s列表頁(yè),可以看到剛才創(chuàng)建的新合約陌上花開(kāi)A。

點(diǎn)擊Mist上面的發(fā)送,我們先給帳戶0xd29adaadf3a40fd0b68c83c222c10d3ea637dce0轉(zhuǎn)入100個(gè)以太幣。

操作成功以后,我們能夠在錢包頁(yè)面看到Account 4已經(jīng)有了100以太幣。

使用以太幣購(gòu)買代幣

接下來(lái),我們進(jìn)入合約頁(yè)面,使用以太幣購(gòu)買陌上花開(kāi)A代幣,進(jìn)入合約界面后,我們能夠看到代幣上的以太幣是0 ether,在右側(cè)選擇Buy方法,Execut from選擇Account 4,在Send ether輸入10個(gè)以太幣,點(diǎn)擊 執(zhí)行。

執(zhí)行成功以后,能夠看到當(dāng)前頁(yè)面自動(dòng)刷新,合約中已經(jīng)有了10 ether,代幣的總量不變

再次回到 錢包 頁(yè)面,可以看到Account 4已經(jīng)從100 ether變成了90 ether,并且多了一個(gè)代幣圖標(biāo)。

點(diǎn)擊Account 4帳號(hào)進(jìn)去,可以看到一些詳細(xì)信息,ether的總量是89,999081514而不是90,是因?yàn)閳?zhí)行合約的時(shí)候,我們會(huì)消費(fèi)一定的gas。我們?cè)O(shè)置的費(fèi)率是1:4,所以10 ether,只可以購(gòu)買2.5個(gè)陌上花開(kāi)A代幣,最小單位也是wei,所以是2,500000000000000000。

賣出代幣

進(jìn)入合約界面后,我們能夠看到代幣上的以太幣是10 ether,在右側(cè)選擇Sell方法,在Amount處輸入2000000000000000000(因?yàn)槲覀儎偛刨?gòu)買了2.5個(gè)代幣,現(xiàn)在賣出2個(gè),賣出的最小單位是wei),Execut from選擇Account 4,點(diǎn)擊 執(zhí)行。

執(zhí)行以后,在代幣的詳情頁(yè)面,能夠看到從10 ether變成了6 ether,因?yàn)閯偛臕ccount 4賣出了 2 個(gè)陌上花開(kāi)A代幣,而我們?cè)O(shè)置的賣價(jià)是 1個(gè)代幣 能賣出 2個(gè)以太幣。

再次回到Account 4的詳情頁(yè)面,能夠看到以太幣變成了 93,998273026,而 陌上花開(kāi)A 代幣的數(shù)量,變成了 0,500000000000000000。

注:Account4使用10個(gè)以太幣購(gòu)買了2.5個(gè)代幣,如果交易機(jī)制沒(méi)有手續(xù)費(fèi),Account4賣出2.5個(gè)代幣仍然會(huì)獲得10個(gè)以太幣。而這里通過(guò)設(shè)置買價(jià)4和賣價(jià)2,Account4賣出2.5個(gè)代幣只會(huì)獲得5個(gè)以太幣。代幣合約利用手續(xù)費(fèi)賺取了5個(gè)以太幣。


pragma solidity 0.4.24;

interface tokenRecipient { function receiveApproval(address _from, uint256 _value, address _token, bytes _extraData) external; }

/**

* owned 是一個(gè)管理者

*/

contract owned {

? ? address public owner;

? ? /**

? ? * 初臺(tái)化構(gòu)造函數(shù)

? ? */

? ? constructor () public {

? ? ? ? owner = msg.sender;

? ? }

? ? /**

? ? * 判斷當(dāng)前合約調(diào)用者是否是管理員

? ? */

? ? modifier onlyOwner {

? ? ? ? require (msg.sender == owner);

? ? ? ? _;

? ? }

? ? /**

? ? * 指派一個(gè)新的管理員

? ? * @param? newOwner address 新的管理員帳戶地址

? ? */

? ? function transferOwnership(address newOwner) onlyOwner public {

? ? ? ? if (newOwner != address(0)) {

? ? ? ? owner = newOwner;

? ? ? }

? ? }

}

/**

* @title 基礎(chǔ)版的代幣合約

*/

contract token {

? ? /* 公共變量 */

? ? string public standard = 'https://mshk.top';

? ? string public name; //代幣名稱

? ? string public symbol; //代幣符號(hào)比如'$'

? ? uint8 public decimals = 18;? //代幣單位,展示的小數(shù)點(diǎn)后面多少個(gè)0,和以太幣一樣后面是是18個(gè)0

? ? uint256 public totalSupply; //代幣總量

? ? /*記錄所有余額的映射*/

? ? mapping (address => uint256) public balanceOf;

? ? mapping (address => mapping (address => uint256)) public allowance;

? ? /* 在區(qū)塊鏈上創(chuàng)建一個(gè)事件,用以通知客戶端*/

? ? event Transfer(address indexed from, address indexed to, uint256 value);? //轉(zhuǎn)帳通知事件

? ? event Burn(address indexed from, uint256 value);? //減去用戶余額事件

? ? /* 初始化合約,并且把初始的所有代幣都給這合約的創(chuàng)建者

? ? * @param initialSupply 代幣的總數(shù)

? ? * @param tokenName 代幣名稱

? ? * @param tokenSymbol 代幣符號(hào)

? ? */

? ? constructor (uint256 initialSupply, string tokenName, string tokenSymbol) public {

? ? ? ? //初始化總量

? ? ? ? totalSupply = initialSupply * 10 ** uint256(decimals);? ? //以太幣是10^18,后面18個(gè)0,所以默認(rèn)decimals是18

? ? ? ? //給指定帳戶初始化代幣總量,初始化用于獎(jiǎng)勵(lì)合約創(chuàng)建者

? ? ? ? //balanceOf[msg.sender] = totalSupply;

? ? ? ? balanceOf[this] = totalSupply;

? ? ? ? name = tokenName;

? ? ? ? symbol = tokenSymbol;

? ? }

? ? /**

? ? * 私有方法從一個(gè)帳戶發(fā)送給另一個(gè)帳戶代幣

? ? * @param? _from address 發(fā)送代幣的地址

? ? * @param? _to address 接受代幣的地址

? ? * @param? _value uint256 接受代幣的數(shù)量

? ? */

? ? function _transfer(address _from, address _to, uint256 _value) internal {

? ? ? //避免轉(zhuǎn)帳的地址是0x0

? ? ? require(_to != 0x0);

? ? ? //檢查發(fā)送者是否擁有足夠余額

? ? ? require(balanceOf[_from] >= _value);

? ? ? //檢查是否溢出

? ? ? require(balanceOf[_to] + _value > balanceOf[_to]);

? ? ? //保存數(shù)據(jù)用于后面的判斷

? ? ? uint previousBalances = balanceOf[_from] + balanceOf[_to];

? ? ? //從發(fā)送者減掉發(fā)送額

? ? ? balanceOf[_from] -= _value;

? ? ? //給接收者加上相同的量

? ? ? balanceOf[_to] += _value;

? ? ? //通知任何監(jiān)聽(tīng)該交易的客戶端

? ? ? emit Transfer(_from, _to, _value);

? ? ? //判斷買、賣雙方的數(shù)據(jù)是否和轉(zhuǎn)換前一致

? ? ? assert(balanceOf[_from] + balanceOf[_to] == previousBalances);

? ? }

? ? /**

? ? * 從主帳戶合約調(diào)用者發(fā)送給別人代幣

? ? * @param? _to address 接受代幣的地址

? ? * @param? _value uint256 接受代幣的數(shù)量

? ? */

? ? function transfer(address _to, uint256 _value) public {

? ? ? ? _transfer(msg.sender, _to, _value);

? ? }

? ? /**

? ? * 從某個(gè)指定的帳戶中,向另一個(gè)帳戶發(fā)送代幣

? ? *

? ? * 調(diào)用過(guò)程,會(huì)檢查設(shè)置的允許最大交易額

? ? *

? ? * @param? _from address 發(fā)送者地址

? ? * @param? _to address 接受者地址

? ? * @param? _value uint256 要轉(zhuǎn)移的代幣數(shù)量

? ? * @return success? ? ? ? 是否交易成功

? ? */

? ? function transferFrom(address _from, address _to, uint256 _value) public returns (bool success) {

? ? ? ? //檢查發(fā)送者是否擁有足夠余額

? ? ? ? require(_value <= allowance[_from][msg.sender]);? // Check allowance

? ? ? ? allowance[_from][msg.sender] -= _value;

? ? ? ? _transfer(_from, _to, _value);

? ? ? ? return true;

? ? }

? ? /**

? ? * 設(shè)置帳戶允許支付的最大金額

? ? *

? ? * 一般在智能合約的時(shí)候,避免支付過(guò)多,造成風(fēng)險(xiǎn)

? ? *

? ? * @param _spender 帳戶地址

? ? * @param _value 金額

? ? */

? ? function approve(address _spender, uint256 _value) public returns (bool success) {

? ? ? ? allowance[msg.sender][_spender] = _value;

? ? ? ? return true;

? ? }

? ? /**

? ? * 設(shè)置帳戶允許支付的最大金額

? ? *

? ? * 一般在智能合約的時(shí)候,避免支付過(guò)多,造成風(fēng)險(xiǎn),加入時(shí)間參數(shù),可以在 tokenRecipient 中做其他操作

? ? *

? ? * @param _spender 帳戶地址

? ? * @param _value 金額

? ? * @param _extraData 操作的時(shí)間

? ? */

? ? 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;

? ? ? ? }

? ? }

? ? /**

? ? * 減少代幣調(diào)用者的余額

? ? *

? ? * 操作以后是不可逆的

? ? *

? ? * @param _value 要?jiǎng)h除的數(shù)量

? ? */

? ? function burn(uint256 _value) public returns (bool success) {

? ? ? ? //檢查帳戶余額是否大于要減去的值

? ? ? ? require(balanceOf[msg.sender] >= _value);? // Check if the sender has enough

? ? ? ? //給指定帳戶減去余額

? ? ? ? balanceOf[msg.sender] -= _value;

? ? ? ? //代幣問(wèn)題做相應(yīng)扣除

? ? ? ? totalSupply -= _value;

? ? ? ? emit Burn(msg.sender, _value);

? ? ? ? return true;

? ? }

? ? /**

? ? * 刪除帳戶的余額(含其他帳戶)

? ? *

? ? * 刪除以后是不可逆的

? ? *

? ? * @param _from 要操作的帳戶地址

? ? * @param _value 要減去的數(shù)量

? ? */

? ? 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;

? ? ? ? emit Burn(_from, _value);

? ? ? ? return true;

? ? }

? ? /**

? ? * 匿名方法,預(yù)防有人向這合約發(fā)送以太幣

? ? */

? ? /*function() {

? ? ? ? //return;? ? // Prevents accidental sending of ether

? ? }*/

}

/**

* @title 高級(jí)版代幣

* 增加凍結(jié)用戶、挖礦、根據(jù)指定匯率購(gòu)買(售出)代幣價(jià)格的功能

*/

contract MyAdvancedToken is owned, token {

? ? //賣出的匯率,一個(gè)代幣,可以賣出多少個(gè)以太幣,單位是wei

? ? uint256 public sellPrice;

? ? //買入的匯率,1個(gè)以太幣,可以買幾個(gè)代幣

? ? uint256 public buyPrice;

? ? //是否凍結(jié)帳戶的列表

? ? mapping (address => bool) public frozenAccount;

? ? //定義一個(gè)事件,當(dāng)有資產(chǎn)被凍結(jié)的時(shí)候,通知正在監(jiān)聽(tīng)事件的客戶端

? ? event FrozenFunds(address target, bool frozen);

? ? /*初始化合約,并且把初始的所有的令牌都給這合約的創(chuàng)建者

? ? * @param initialSupply 所有幣的總數(shù)

? ? * @param tokenName 代幣名稱

? ? * @param tokenSymbol 代幣符號(hào)

? ? * @param centralMinter 是否指定其他帳戶為合約所有者,為0是去中心化

? ? */

? ? constructor (

? ? ? uint256 initialSupply,

? ? ? string tokenName,

? ? ? string tokenSymbol,

? ? ? address centralMinter

? ? ) token (initialSupply, tokenName, tokenSymbol) public {

? ? ? ? //設(shè)置合約的管理者

? ? ? ? if(centralMinter != 0 ) owner = centralMinter;

? ? ? ? sellPrice = 2;? ? //設(shè)置1個(gè)單位的代幣(單位是wei),能夠賣出2個(gè)以太幣

? ? ? ? buyPrice = 4;? ? ? //設(shè)置1個(gè)以太幣,可以買0.25個(gè)代幣

? ? }

? ? /**

? ? * 私有方法,從指定帳戶轉(zhuǎn)出余額

? ? * @param? _from address 發(fā)送代幣的地址

? ? * @param? _to address 接受代幣的地址

? ? * @param? _value uint256 接受代幣的數(shù)量

? ? */

? ? function _transfer(address _from, address _to, uint _value) internal {

? ? ? ? //避免轉(zhuǎn)帳的地址是0x0

? ? ? ? require (_to != 0x0);

? ? ? ? //檢查發(fā)送者是否擁有足夠余額

? ? ? ? require (balanceOf[_from] > _value);

? ? ? ? //檢查是否溢出

? ? ? ? require (balanceOf[_to] + _value > balanceOf[_to]);

? ? ? ? //檢查 凍結(jié)帳戶

? ? ? ? require(!frozenAccount[_from]);

? ? ? ? require(!frozenAccount[_to]);

? ? ? ? //從發(fā)送者減掉發(fā)送額

? ? ? ? balanceOf[_from] -= _value;

? ? ? ? //給接收者加上相同的量

? ? ? ? balanceOf[_to] += _value;

? ? ? ? //通知任何監(jiān)聽(tīng)該交易的客戶端

? ? ? ? emit Transfer(_from, _to, _value);

? ? }

? ? /**

? ? * 合約擁有者,可以為指定帳戶創(chuàng)造一些代幣

? ? * @param? target address 帳戶地址

? ? * @param? mintedAmount uint256 增加的金額(單位是wei)

? ? */

? ? function mintToken(address target, uint256 mintedAmount) onlyOwner public {

? ? ? ? //給指定地址增加代幣,同時(shí)總量也相加

? ? ? ? balanceOf[target] += mintedAmount;

? ? ? ? totalSupply += mintedAmount;

? ? ? ? emit Transfer(0, this, mintedAmount);

? ? ? ? emit Transfer(this, target, mintedAmount);

? ? }

? ? /**

? ? * 增加凍結(jié)帳戶名稱

? ? *

? ? * 你可能需要監(jiān)管功能以便你能控制誰(shuí)可以/誰(shuí)不可以使用你創(chuàng)建的代幣合約

? ? *

? ? * @param? target address 帳戶地址

? ? * @param? freeze bool? ? 是否凍結(jié)

? ? */

? ? function freezeAccount(address target, bool freeze) onlyOwner public {

? ? ? ? frozenAccount[target] = freeze;

? ? ? ? emit FrozenFunds(target, freeze);

? ? }

? ? /**

? ? * 設(shè)置買賣價(jià)格

? ? *

? ? * 如果你想讓ether(或其他代幣)為你的代幣進(jìn)行背書(shū),以便可以市場(chǎng)價(jià)自動(dòng)化買賣代幣,我們可以這么做。如果要使用浮動(dòng)的價(jià)格,也可以在這里設(shè)置

? ? *

? ? * @param newSellPrice 新的賣出價(jià)格

? ? * @param newBuyPrice 新的買入價(jià)格

? ? */

? ? function setPrices(uint256 newSellPrice, uint256 newBuyPrice) onlyOwner public {

? ? ? ? sellPrice = newSellPrice;

? ? ? ? buyPrice = newBuyPrice;

? ? }

? ? /**

? ? * 使用以太幣購(gòu)買代幣

? ? */

? ? function buy() payable public {

? ? ? uint amount = msg.value / buyPrice;

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

? ? }

? ? /**

? ? * @dev 賣出代幣

? ? * @return 要賣出的數(shù)量(單位是wei)

? ? */

? ? function sell(uint256 amount) public {

? ? ? ? //檢查合約的余額是否充足

? ? ? ? require(address(this).balance >= amount * sellPrice);

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

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

? ? }

}.


以上買賣未調(diào)試通過(guò)

以太坊開(kāi)發(fā)(十三)代幣示例及講解

Go-Ethereum 1.7.2 結(jié)合 Mist 0.9.2 實(shí)現(xiàn)代幣智能合約的實(shí)例

以太坊使用數(shù)字貨幣(通證)完成去中心化投票DApp

基于以太坊發(fā)布屬于自己的數(shù)字貨幣(代幣)完整版

給代幣添加高級(jí)功能-代幣管理、增發(fā)、兌換、凍結(jié)等

Create your own crypto-currency

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容