(注:本文是在原文的基礎(chǔ)上贞瞒,根據(jù)個人的理解弄跌,修改部分內(nèi)容并添加了一些注釋)
買賣部分代碼未調(diào)試通過
基礎(chǔ)版的代幣合約
下面是一個最簡單的代幣合約代碼煌恢,主要介紹可以看注釋:
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;
? ? }
? ? /**
? ? * 私有方法從一個帳戶發(fā)送給另一個帳戶代幣
? ? * @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);
? ? }
}
接下來我們將上面的合約代碼枢贿,通過Mist部署到我們的私有鏈
首先如下圖中殉农,點(diǎn)擊合約->部署新合約:
然后如下面的兩張圖,選擇創(chuàng)建合約的帳戶局荚,將上面的代碼貼到SOLIDITY合約原始代碼處超凳,在右側(cè)選擇要部署的合約token,在token的下面Initial Supply處耀态,輸入我們要初始化的金額5000用于獎勵合約創(chuàng)建者轮傍,然后在頁面的最下面,點(diǎn)擊部署首装,的彈出的層中创夜,輸入創(chuàng)建合約這個帳號的密碼,輸入正確以后仙逻,合約創(chuàng)建成功挥下。
創(chuàng)建一個合約以后揍魂,再點(diǎn)擊Mist右側(cè)的合約,然后在定制化合約的下面棚瘟,可以看到我們剛剛創(chuàng)建的合約TOKEN,如下圖:
注意现斋,在合約下面也有一串0x開頭的地址,這個就相當(dāng)于一個錢包的地址偎蘸。在以太坊中庄蹋,合約也相當(dāng)于一個帳戶。
點(diǎn)擊TOKEN迷雪,進(jìn)入到合約里限书。在下面的Balance Of處,輸入剛才創(chuàng)建合約帳戶的地址0xa18e688326ab13b6147ce3ca2213db143a4ec2ee章咧,可以看到是有5000個代幣在里面倦西,如下圖:
在代幣創(chuàng)建的時候,初始值我們設(shè)置的是5000赁严,所以只有創(chuàng)建帳戶的地址有代幣扰柠,而輸入其他帳戶的地址,如0xc81896af13449a82f22699311df4ec4b48c07718疼约,是沒有值的卤档。
接下來,我們向0xc81896af13449a82f22699311df4ec4b48c07718這個帳戶地址程剥,轉(zhuǎn)入一些代幣劝枣。點(diǎn)擊右側(cè)選擇函數(shù)->選擇Transfer,在_to中輸入0xc81896af13449a82f22699311df4ec4b48c07718织鲸,在_value中輸入500舔腾,然后點(diǎn)擊執(zhí)行,在彈出的層中輸入調(diào)用合約帳戶的密碼搂擦,確認(rèn)操作舰始。
我們能夠看到實(shí)際調(diào)用合約的過程中炕吸,會花費(fèi)一定的gas拢肆,gas和以太幣會根據(jù)區(qū)塊的算力有一個計算公式郁岩,gas一般用于獎勵給挖礦者滔驶。
在transfer方法中这溅,我們設(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);}
這時工扎,再次進(jìn)入合約徘钥,在Balance Of處,輸入兩個帳戶的地址肢娘,可以看到呈础,余額都發(fā)生的變化舆驶,如下圖:
改善代幣
通過上面的操作,我們已經(jīng)可以將合約代碼而钞,通過 Mist 部署到我們創(chuàng)建的私有鏈中沙廉,同樣如果部署到生產(chǎn)環(huán)境,只需要連上以太坊的網(wǎng)絡(luò)臼节,同樣的方法也可以將你的合約撬陵,部署到生產(chǎn)環(huán)境中,不過要根據(jù)代碼的大小网缝,花費(fèi)一些以太幣巨税。
實(shí)際使用過程中,交易的過程粉臊,需要通知到客戶端草添,并且記錄到區(qū)塊中,我們可以使用event事件來指定扼仲,如下代碼進(jìn)行聲明:
//在區(qū)塊鏈上創(chuàng)建一個事件远寸,用以通知客戶端eventTransfer(address indexed from, address indexed to, uint256 value);
設(shè)置一些代幣的基本信息
/* 公共變量 */stringpublicstandard ='https://mshk.top';stringpublicname;//代幣名稱stringpublicsymbol;//代幣符號比如'$'uint8publicdecimals =18;//代幣單位,展示的小數(shù)點(diǎn)后面多少個0,和以太幣一樣后面是是18個0uint256publictotalSupply;//代幣總量
某些特定的場景中犀盟,不允許某個帳戶花費(fèi)超過指定的上限而晒,避免大額支出,我們可以添加一個approve方法阅畴,來設(shè)置一個允許支出最大金額的列表倡怎。
注:根據(jù)個人的理解,approve是其他合約調(diào)用此合約贱枣,或者是代理监署,例如交易所,使用你的賬戶時纽哥,你可以設(shè)置一個代幣數(shù)量钠乏。他們只能對你設(shè)置的數(shù)量的代幣進(jìn)行操作,不知道這樣理解是否準(zhǔn)確春塌。下面是一個對approve晓避、allowance,以及后面的transferFrom的解釋:
注:approve只壳、transferFrom及allowance解釋:
賬戶A有1000個ETH俏拱,想允許B賬戶隨意調(diào)用100個ETH。A賬戶按照以下形式調(diào)用approve函數(shù)approve(B,100)吼句。當(dāng)B賬戶想用這100個ETH中的10個ETH給C賬戶時锅必,則調(diào)用transferFrom(A, C, 10)。這時調(diào)用allowance[A][B]可以查看B賬戶還能夠調(diào)用A賬戶多少個token惕艳。
mapping (address => mapping (address => uint256))publicallowance;/** * 設(shè)置帳戶允許支付的最大金額 * * 一般在智能合約的時候搞隐,避免支付過多驹愚,造成風(fēng)險 * *@param_spender 帳戶地址 *@param_value 金額 */functionapprove(address _spender, uint256 _value)publicreturns(bool success){? ? allowance[msg.sender][_spender] = _value;returntrue;}
同樣在solidity中,合約之間也可以相互調(diào)用劣纲,我們可以增加一個approveAndCall方法逢捺,用于在設(shè)置帳戶最大支出金額后,可以做一些其他操作癞季。
interfacetokenRecipient{functionreceiveApproval(address _from, uint256 _value, address _token, bytes _extraData)public; }/** * 設(shè)置帳戶允許支付的最大金額 * * 一般在智能合約的時候蒸甜,避免支付過多,造成風(fēng)險 * *@param_spender 帳戶地址 *@param_value 金額 */functionapprove(address _spender, uint256 _value)publicreturns(bool success){? ? allowance[msg.sender][_spender] = _value;returntrue;}/** * 設(shè)置帳戶允許支付的最大金額 * * 一般在智能合約的時候余佛,避免支付過多柠新,造成風(fēng)險,加入時間參數(shù)辉巡,可以在 tokenRecipient 中做其他操作 * *@param_spender 帳戶地址 *@param_value 金額 *@param_extraData 操作的時間 */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;? ? }}
我們可以增加一個burn方法恨憎,用于管理員減去指定帳戶的指定金額。進(jìn)行該方法操作時郊楣,通知客戶端記錄到區(qū)塊鏈中憔恳。
注:代碼并沒有判斷調(diào)用者是否為管理員。
注:代理B在調(diào)用burnFrom刪除A賬戶余額時净蚤,也需要刪除A授權(quán)給自己的可調(diào)用余額數(shù)钥组。
//減去用戶余額事件event Burn(address indexed from, uint256 value);/** * 減少代幣調(diào)用者的余額 * * 操作以后是不可逆的 * *@param_value 要刪除的數(shù)量 */functionburn(uint256 _value)publicreturns(bool success){//檢查帳戶余額是否大于要減去的值require(balanceOf[msg.sender] >= _value);// Check if the sender has enough//給指定帳戶減去余額balanceOf[msg.sender] -= _value;//代幣問題做相應(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;//代幣符號比如'$'uint8publicdecimals =18;//代幣單位,展示的小數(shù)點(diǎn)后面多少個0,和以太幣一樣后面是是18個0uint256publictotalSupply;//代幣總量/*記錄所有余額的映射*/mapping (address => uint256)publicbalanceOf;? ? mapping (address => mapping (address => uint256))publicallowance;/* 在區(qū)塊鏈上創(chuàng)建一個事件今瀑,用以通知客戶端*/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 代幣符號? ? */functiontoken(uint256 initialSupply, string tokenName, string tokenSymbol)public{//初始化總量totalSupply = initialSupply *10** uint256(decimals);//以太幣是10^18,后面18個0橘荠,所以默認(rèn)decimals是18//給指定帳戶初始化代幣總量屿附,初始化用于獎勵合約創(chuàng)建者balanceOf[msg.sender] = totalSupply;? ? ? ? name = tokenName;? ? ? ? symbol = tokenSymbol;? ? }/**? ? * 私有方法從一個帳戶發(fā)送給另一個帳戶代幣? ? *@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)聽該交易的客戶端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);? ? }/**? ? * 從某個指定的帳戶中哥童,向另一個帳戶發(fā)送代幣? ? *? ? * 調(diào)用過程挺份,會檢查設(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è)置帳戶允許支付的最大金額? ? *? ? * 一般在智能合約的時候,避免支付過多贮懈,造成風(fēng)險? ? *? ? *@param_spender 帳戶地址? ? *@param_value 金額? ? */functionapprove(address _spender, uint256 _value)publicreturns(bool success){? ? ? ? allowance[msg.sender][_spender] = _value;returntrue;? ? }/**? ? * 設(shè)置帳戶允許支付的最大金額? ? *? ? * 一般在智能合約的時候匀泊,避免支付過多,造成風(fēng)險朵你,加入時間參數(shù)各聘,可以在 tokenRecipient 中做其他操作? ? *? ? *@param_spender 帳戶地址? ? *@param_value 金額? ? *@param_extraData 操作的時間? ? */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 要刪除的數(shù)量? ? */functionburn(uint256 _value)publicreturns(bool success){//檢查帳戶余額是否大于要減去的值require(balanceOf[msg.sender] >= _value);// Check if the sender has enough//給指定帳戶減去余額balanceOf[msg.sender] -= _value;//代幣問題做相應(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輸入我們的代幣名稱陌上花開毛仪,Token symbol代幣符號我們輸入$$,然后點(diǎn)擊部署,輸入部署帳戶的密碼芯勘。
部署合約以后箱靴,我們能夠在合約頁面看到剛才創(chuàng)建的合約。
點(diǎn)擊合約名稱荷愕,可以看到合約的一些基本信息衡怀,以及合約和操作函數(shù)
我們能夠在Mist上方的錢包中的主帳號這里看到有個小圖標(biāo),說明主帳戶已經(jīng)有了代幣安疗,其他帳戶是沒有這個圖標(biāo)的
點(diǎn)擊進(jìn)入主帳號以后抛杨,我們就可以看到主帳戶已經(jīng)擁有的代幣和以太幣的數(shù)量,因?yàn)槲覀兪菂⒖家蕴珟胚M(jìn)行設(shè)置荐类,最小單位是wei怖现,所以小數(shù)點(diǎn)后面有18個0。
接下來玉罐,我們向另一個帳戶發(fā)送一些陌上花開幣屈嗤,點(diǎn)擊Mist上方的發(fā)送,輸入發(fā)送的帳戶地址吊输,輸入數(shù)量500饶号,選擇發(fā)送的是陌上花開幣,點(diǎn)擊發(fā)送季蚂,如下圖
再次回到錢包中茫船,我們可以看到,另一個帳戶也有了一個代幣的圖標(biāo)扭屁,說明代幣已經(jīng)轉(zhuǎn)入成功透硝。
現(xiàn)在你擁有了自己的代幣,也可以做轉(zhuǎn)入轉(zhuǎn)出操作疯搅”羯可以被用于價值交換,或者工作時間追蹤或者其他項(xiàng)目。
高級版的代幣功能
雖然區(qū)塊鏈?zhǔn)侨ブ行幕尼E罚菍?shí)現(xiàn)對代幣(合約)的管理罪治,也在許多應(yīng)用中有需求,為了對代幣進(jìn)行管理礁蔗,首先需要給合約添加一個管理者觉义。
** * owned 是一個管理者 */contract owned {? ? addresspublicowner;/**
? ? * 初臺化構(gòu)造函數(shù)
? ? */functionowned(){? ? ? ? owner = msg.sender;? ? }/**
? ? * 判斷當(dāng)前合約調(diào)用者是否是管理員
? ? */modifier onlyOwner {require(msg.sender == owner);? ? ? ? _;? ? }/**? ? * 指派一個新的管理員? ? *@paramnewOwner address 新的管理員帳戶地址? ? */functiontransferOwnership(address newOwner)onlyOwner{if(newOwner != address(0)) {? ? ? ? owner = newOwner;? ? ? }? ? }}
上面的代碼是一個非常簡單的合約,我們可以在后面的代碼中浴井,使用繼承來實(shí)現(xiàn)后續(xù)的功能晒骇。
/** *@title高級版代幣 * 增加凍結(jié)用戶、挖礦、根據(jù)指定匯率購買(售出)代幣價格的功能 */contract MyAdvancedToken is owned{}
在MyAdvancedToken的所有方法中洪囤,可以使用owned的變量owner和modifier onlyOwner徒坡。
去中心化的管理者
我們也可以在構(gòu)造函數(shù)中設(shè)置是否需要一個去中心化的管理者。
/*初始化合約瘤缩,并且把初始的所有的令牌都給這合約的創(chuàng)建者 *@paraminitialSupply 所有幣的總數(shù) *@paramtokenName 代幣名稱 *@paramtokenSymbol 代幣符號 *@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{//給指定地址增加代幣,同時總量也相加balanceOf[target] += mintedAmount;? ? totalSupply += mintedAmount;}
在方法的最后有一個onlyOwner府怯,說明mintToken是繼承了onlyOwner方法刻诊,會先調(diào)用modifier onlyOwner方法,然后將mintToken方法的內(nèi)容牺丙,插入到下劃線 _ 處調(diào)用坏逢。
凍結(jié)資產(chǎn)
有的場景中,某些用戶違反了規(guī)定赘被,需要凍結(jié)/解凍帳戶是整,不想讓他使用已經(jīng)擁有的代幣.可以增加以下代碼來控制:
//是否凍結(jié)帳戶的列表mapping (address => bool)publicfrozenAccount;//定義一個事件,當(dāng)有資產(chǎn)被凍結(jié)的時候民假,通知正在監(jiān)聽事件的客戶端event FrozenFunds(address target, bool frozen);/** * 增加凍結(jié)帳戶名稱 * * 你可能需要監(jiān)管功能以便你能控制誰可以/誰不可以使用你創(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ī)制浮入。有了這個功能,我們的合約就可以在一買一賣中賺利潤了羊异。
//賣出的匯率,一個代幣事秀,可以賣出多少個以太幣,單位是weiuint256publicsellPrice;//買入的匯率,1個以太幣野舶,可以買幾個代幣uint256publicbuyPrice;/** * 設(shè)置買賣價格 * * 如果你想讓ether(或其他代幣)為你的代幣進(jìn)行背書,以便可以市場價自動化買賣代幣,我們可以這么做易迹。如果要使用浮動的價格,也可以在這里設(shè)置 * *@paramnewSellPrice 新的賣出價格 *@paramnewBuyPrice 新的買入價格 */functionsetPrices(uint256 newSellPrice, uint256 newBuyPrice)onlyOwner{? ? sellPrice = newSellPrice;? ? buyPrice = newBuyPrice;}
然后增加買平道、賣的方法睹欲,每一次的交易,都會消耗掉一定的ether一屋。在 Solidity 0.4.0 之后窘疮,要接收ether的函數(shù)都要加一個payable屬性,如果你開放的合約冀墨,需要別人轉(zhuǎn)錢給你闸衫,就需要加payable。
下面的方法诽嘉,不會增加代幣蔚出,只是改變調(diào)用合約者的代幣數(shù)量弟翘,買、賣的價格單位不是ether骄酗,而是wei稀余,這是以太幣中最小的單位(就像美元里的美分,比特幣里的聰)。1 ether = 1000000000000000000 wei酥筝。因此使用ether設(shè)置價格的時候,在最后加18個0。
當(dāng)創(chuàng)建合約的時候,發(fā)送足夠多的ether作為代幣的背書,否則你的合約就是破產(chǎn)的,你的用戶就不能夠賣掉他們的代幣雏门。
/**
* 使用以太幣購買代幣
*/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的自動補(bǔ)充
以太坊中的交易時需要gas(支付給礦工的費(fèi)用嘿歌,費(fèi)用以ether來支付)。而如果用戶沒有以太幣茁影,只有代幣的情況(或者我們想向用戶隱藏以太坊的細(xì)節(jié))宙帝,就需要自動補(bǔ)充gas的功能。這個功能將使我們代幣更加好用募闲。
自動補(bǔ)充的邏輯是這樣了步脓,在執(zhí)行交易之前,我們判斷用戶的余額(用來支付礦工的費(fèi)用)浩螺,如果用戶的余額非常少(低于某個閾值時)可能影響到交易進(jìn)行靴患,合約自動售出一部分代幣來補(bǔ)充余額,以幫助用戶順利完成交易要出。
先來設(shè)定余額閾值:
uint minBalanceForAccounts;functionsetMinBalance(uint minimumBalanceInFinney)onlyOwner{? ? ? ? minBalanceForAccounts = minimumBalanceInFinney *1finney;? ? }
finney 是貨幣單位 1 finney = 0.001eth
然后交易中加入對用戶的余額的判斷鸳君。
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 是一個管理者
*/contract owned {? ? addresspublicowner;/**
? ? * 初臺化構(gòu)造函數(shù)
? ? */functionowned()public{? ? ? ? owner = msg.sender;? ? }/**
? ? * 判斷當(dāng)前合約調(diào)用者是否是管理員
? ? */modifier onlyOwner {require(msg.sender == owner);? ? ? ? _;? ? }/**? ? * 指派一個新的管理員? ? *@paramnewOwner address 新的管理員帳戶地址? ? */functiontransferOwnership(address newOwner)onlyOwnerpublic{if(newOwner != address(0)) {? ? ? ? owner = newOwner;? ? ? }? ? }}/** *@title基礎(chǔ)版的代幣合約 */contract token {/* 公共變量 */stringpublicstandard ='https://mshk.top';? ? stringpublicname;//代幣名稱stringpublicsymbol;//代幣符號比如'$'uint8publicdecimals =18;//代幣單位,展示的小數(shù)點(diǎn)后面多少個0,和以太幣一樣后面是是18個0uint256publictotalSupply;//代幣總量/*記錄所有余額的映射*/mapping (address => uint256)publicbalanceOf;? ? mapping (address => mapping (address => uint256))publicallowance;/* 在區(qū)塊鏈上創(chuàng)建一個事件患蹂,用以通知客戶端*/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 代幣符號? ? */functiontoken(uint256 initialSupply, string tokenName, string tokenSymbol)public{//初始化總量totalSupply = initialSupply *10** uint256(decimals);//以太幣是10^18,后面18個0传于,所以默認(rèn)decimals是18//給指定帳戶初始化代幣總量囱挑,初始化用于獎勵合約創(chuàng)建者//balanceOf[msg.sender] = totalSupply;balanceOf[this] = totalSupply;? ? ? ? name = tokenName;? ? ? ? symbol = tokenSymbol;? ? }/**? ? * 私有方法從一個帳戶發(fā)送給另一個帳戶代幣? ? *@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)聽該交易的客戶端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);? ? }/**? ? * 從某個指定的帳戶中沼溜,向另一個帳戶發(fā)送代幣? ? *? ? * 調(diào)用過程平挑,會檢查設(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è)置帳戶允許支付的最大金額? ? *? ? * 一般在智能合約的時候,避免支付過多系草,造成風(fēng)險? ? *? ? *@param_spender 帳戶地址? ? *@param_value 金額? ? */functionapprove(address _spender, uint256 _value)publicreturns(bool success){? ? ? ? allowance[msg.sender][_spender] = _value;returntrue;? ? }/**? ? * 設(shè)置帳戶允許支付的最大金額? ? *? ? * 一般在智能合約的時候弹惦,避免支付過多,造成風(fēng)險悄但,加入時間參數(shù)棠隐,可以在 tokenRecipient 中做其他操作? ? *? ? *@param_spender 帳戶地址? ? *@param_value 金額? ? *@param_extraData 操作的時間? ? */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 要刪除的數(shù)量? ? */functionburn(uint256 _value)publicreturns(bool success){//檢查帳戶余額是否大于要減去的值require(balanceOf[msg.sender] >= _value);// Check if the sender has enough//給指定帳戶減去余額balanceOf[msg.sender] -= _value;//代幣問題做相應(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高級版代幣 * 增加凍結(jié)用戶檐嚣、挖礦助泽、根據(jù)指定匯率購買(售出)代幣價格的功能 */contract MyAdvancedToken is owned, token {//賣出的匯率,一個代幣啰扛,可以賣出多少個以太幣,單位是weiuint256publicsellPrice;//買入的匯率,1個以太幣嗡贺,可以買幾個代幣uint256publicbuyPrice;//是否凍結(jié)帳戶的列表mapping (address => bool)publicfrozenAccount;//定義一個事件隐解,當(dāng)有資產(chǎn)被凍結(jié)的時候,通知正在監(jiān)聽事件的客戶端event FrozenFunds(address target, bool frozen);/*初始化合約诫睬,并且把初始的所有的令牌都給這合約的創(chuàng)建者? ? *@paraminitialSupply 所有幣的總數(shù)? ? *@paramtokenName 代幣名稱? ? *@paramtokenSymbol 代幣符號? ? *@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個單位的代幣(單位是wei)煞茫,能夠賣出2個以太幣buyPrice =4;//設(shè)置1個以太幣,可以買0.25個代幣}/**? ? * 私有方法摄凡,從指定帳戶轉(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)聽該交易的客戶端Transfer(_from, _to, _value);? ? }/**? ? * 合約擁有者续徽,可以為指定帳戶創(chuàng)造一些代幣? ? *@paramtarget address 帳戶地址? ? *@parammintedAmount uint256 增加的金額(單位是wei)? ? */functionmintToken(address target, uint256 mintedAmount)onlyOwnerpublic{//給指定地址增加代幣,同時總量也相加balanceOf[target] += mintedAmount;? ? ? ? totalSupply += mintedAmount;? ? ? ? Transfer(0, this, mintedAmount);? ? ? ? Transfer(this, target, mintedAmount);? ? }/**? ? * 增加凍結(jié)帳戶名稱? ? *? ? * 你可能需要監(jiān)管功能以便你能控制誰可以/誰不可以使用你創(chuàng)建的代幣合約? ? *? ? *@paramtarget address 帳戶地址? ? *@paramfreeze bool? ? 是否凍結(jié)? ? */functionfreezeAccount(address target, bool freeze)onlyOwnerpublic{? ? ? ? frozenAccount[target] = freeze;? ? ? ? FrozenFunds(target, freeze);? ? }/**? ? * 設(shè)置買賣價格? ? *? ? * 如果你想讓ether(或其他代幣)為你的代幣進(jìn)行背書,以便可以市場價自動化買賣代幣,我們可以這么做亲澡。如果要使用浮動的價格钦扭,也可以在這里設(shè)置? ? *? ? *@paramnewSellPrice 新的賣出價格? ? *@paramnewBuyPrice 新的買入價格? ? */functionsetPrices(uint256 newSellPrice, uint256 newBuyPrice)onlyOwnerpublic{? ? ? ? sellPrice = newSellPrice;? ? ? ? buyPrice = newBuyPrice;? ? }/**
? ? * 使用以太幣購買代幣
? ? */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輸入我們的代幣名稱陌上花開A膀斋,Token symbol代幣符號我們輸入#,然后點(diǎn)擊部署,輸入部署帳戶的密碼痹雅。
創(chuàng)建成功以后概页,我們在合約列表頁,可以看到剛才創(chuàng)建的新合約陌上花開A练慕。
點(diǎn)擊Mist上面的發(fā)送惰匙,我們先給帳戶0xd29adaadf3a40fd0b68c83c222c10d3ea637dce0轉(zhuǎn)入100個以太幣。
操作成功以后铃将,我們能夠在錢包頁面看到Account 4已經(jīng)有了100以太幣项鬼。
使用以太幣購買代幣
接下來,我們進(jìn)入合約頁面劲阎,使用以太幣購買陌上花開A代幣绘盟,進(jìn)入合約界面后,我們能夠看到代幣上的以太幣是0 ether悯仙,在右側(cè)選擇Buy方法龄毡,Execut from選擇Account 4,在Send ether輸入10個以太幣锡垄,點(diǎn)擊 執(zhí)行沦零。
執(zhí)行成功以后,能夠看到當(dāng)前頁面自動刷新货岭,合約中已經(jīng)有了10 ether路操,代幣的總量不變
再次回到 錢包 頁面疾渴,可以看到Account 4已經(jīng)從100 ether變成了90 ether,并且多了一個代幣圖標(biāo)屯仗。
點(diǎn)擊Account 4帳號進(jìn)去搞坝,可以看到一些詳細(xì)信息,ether的總量是89,999081514而不是90魁袜,是因?yàn)閳?zhí)行合約的時候桩撮,我們會消費(fèi)一定的gas。我們設(shè)置的費(fèi)率是1:4,所以10 ether峰弹,只可以購買2.5個陌上花開A代幣,最小單位也是wei店量,所以是2,500000000000000000。
賣出代幣
進(jìn)入合約界面后垮卓,我們能夠看到代幣上的以太幣是10 ether垫桂,在右側(cè)選擇Sell方法师幕,在Amount處輸入2000000000000000000(因?yàn)槲覀儎偛刨徺I了2.5個代幣粟按,現(xiàn)在賣出2個,賣出的最小單位是wei),Execut from選擇Account 4霹粥,點(diǎn)擊 執(zhí)行灭将。
執(zhí)行以后,在代幣的詳情頁面后控,能夠看到從10 ether變成了6 ether庙曙,因?yàn)閯偛臕ccount 4賣出了 2 個陌上花開A代幣,而我們設(shè)置的賣價是 1個代幣 能賣出 2個以太幣浩淘。
再次回到Account 4的詳情頁面捌朴,能夠看到以太幣變成了 93,998273026,而 陌上花開A 代幣的數(shù)量张抄,變成了 0,500000000000000000砂蔽。
注:Account4使用10個以太幣購買了2.5個代幣,如果交易機(jī)制沒有手續(xù)費(fèi)署惯,Account4賣出2.5個代幣仍然會獲得10個以太幣左驾。而這里通過設(shè)置買價4和賣價2,Account4賣出2.5個代幣只會獲得5個以太幣极谊。代幣合約利用手續(xù)費(fèi)賺取了5個以太幣诡右。
pragma solidity 0.4.24;
interface tokenRecipient { function receiveApproval(address _from, uint256 _value, address _token, bytes _extraData) external; }
/**
* owned 是一個管理者
*/
contract owned {
? ? address public owner;
? ? /**
? ? * 初臺化構(gòu)造函數(shù)
? ? */
? ? constructor () public {
? ? ? ? owner = msg.sender;
? ? }
? ? /**
? ? * 判斷當(dāng)前合約調(diào)用者是否是管理員
? ? */
? ? modifier onlyOwner {
? ? ? ? require (msg.sender == owner);
? ? ? ? _;
? ? }
? ? /**
? ? * 指派一個新的管理員
? ? * @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; //代幣符號比如'$'
? ? uint8 public decimals = 18;? //代幣單位,展示的小數(shù)點(diǎn)后面多少個0,和以太幣一樣后面是是18個0
? ? uint256 public totalSupply; //代幣總量
? ? /*記錄所有余額的映射*/
? ? mapping (address => uint256) public balanceOf;
? ? mapping (address => mapping (address => uint256)) public allowance;
? ? /* 在區(qū)塊鏈上創(chuàng)建一個事件轻猖,用以通知客戶端*/
? ? 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 代幣符號
? ? */
? ? constructor (uint256 initialSupply, string tokenName, string tokenSymbol) public {
? ? ? ? //初始化總量
? ? ? ? totalSupply = initialSupply * 10 ** uint256(decimals);? ? //以太幣是10^18,后面18個0咙边,所以默認(rèn)decimals是18
? ? ? ? //給指定帳戶初始化代幣總量桅锄,初始化用于獎勵合約創(chuàng)建者
? ? ? ? //balanceOf[msg.sender] = totalSupply;
? ? ? ? balanceOf[this] = totalSupply;
? ? ? ? name = tokenName;
? ? ? ? symbol = tokenSymbol;
? ? }
? ? /**
? ? * 私有方法從一個帳戶發(fā)送給另一個帳戶代幣
? ? * @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)聽該交易的客戶端
? ? ? 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);
? ? }
? ? /**
? ? * 從某個指定的帳戶中,向另一個帳戶發(fā)送代幣
? ? *
? ? * 調(diào)用過程友瘤,會檢查設(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è)置帳戶允許支付的最大金額
? ? *
? ? * 一般在智能合約的時候翠肘,避免支付過多,造成風(fēng)險
? ? *
? ? * @param _spender 帳戶地址
? ? * @param _value 金額
? ? */
? ? function approve(address _spender, uint256 _value) public returns (bool success) {
? ? ? ? allowance[msg.sender][_spender] = _value;
? ? ? ? return true;
? ? }
? ? /**
? ? * 設(shè)置帳戶允許支付的最大金額
? ? *
? ? * 一般在智能合約的時候辫秧,避免支付過多束倍,造成風(fēng)險,加入時間參數(shù)盟戏,可以在 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;
? ? ? ? }
? ? }
? ? /**
? ? * 減少代幣調(diào)用者的余額
? ? *
? ? * 操作以后是不可逆的
? ? *
? ? * @param _value 要刪除的數(shù)量
? ? */
? ? function burn(uint256 _value) public returns (bool success) {
? ? ? ? //檢查帳戶余額是否大于要減去的值
? ? ? ? require(balanceOf[msg.sender] >= _value);? // Check if the sender has enough
? ? ? ? //給指定帳戶減去余額
? ? ? ? balanceOf[msg.sender] -= _value;
? ? ? ? //代幣問題做相應(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 高級版代幣
* 增加凍結(jié)用戶、挖礦柿究、根據(jù)指定匯率購買(售出)代幣價格的功能
*/
contract MyAdvancedToken is owned, token {
? ? //賣出的匯率,一個代幣邮旷,可以賣出多少個以太幣,單位是wei
? ? uint256 public sellPrice;
? ? //買入的匯率,1個以太幣蝇摸,可以買幾個代幣
? ? uint256 public buyPrice;
? ? //是否凍結(jié)帳戶的列表
? ? mapping (address => bool) public frozenAccount;
? ? //定義一個事件婶肩,當(dāng)有資產(chǎn)被凍結(jié)的時候,通知正在監(jiān)聽事件的客戶端
? ? event FrozenFunds(address target, bool frozen);
? ? /*初始化合約貌夕,并且把初始的所有的令牌都給這合約的創(chuàng)建者
? ? * @param initialSupply 所有幣的總數(shù)
? ? * @param tokenName 代幣名稱
? ? * @param tokenSymbol 代幣符號
? ? * @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個單位的代幣(單位是wei)律歼,能夠賣出2個以太幣
? ? ? ? buyPrice = 4;? ? ? //設(shè)置1個以太幣,可以買0.25個代幣
? ? }
? ? /**
? ? * 私有方法啡专,從指定帳戶轉(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)聽該交易的客戶端
? ? ? ? emit Transfer(_from, _to, _value);
? ? }
? ? /**
? ? * 合約擁有者险毁,可以為指定帳戶創(chuàng)造一些代幣
? ? * @param? target address 帳戶地址
? ? * @param? mintedAmount uint256 增加的金額(單位是wei)
? ? */
? ? function mintToken(address target, uint256 mintedAmount) onlyOwner public {
? ? ? ? //給指定地址增加代幣,同時總量也相加
? ? ? ? balanceOf[target] += mintedAmount;
? ? ? ? totalSupply += mintedAmount;
? ? ? ? emit Transfer(0, this, mintedAmount);
? ? ? ? emit Transfer(this, target, mintedAmount);
? ? }
? ? /**
? ? * 增加凍結(jié)帳戶名稱
? ? *
? ? * 你可能需要監(jiān)管功能以便你能控制誰可以/誰不可以使用你創(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è)置買賣價格
? ? *
? ? * 如果你想讓ether(或其他代幣)為你的代幣進(jìn)行背書,以便可以市場價自動化買賣代幣,我們可以這么做们童。如果要使用浮動的價格畔况,也可以在這里設(shè)置
? ? *
? ? * @param newSellPrice 新的賣出價格
? ? * @param newBuyPrice 新的買入價格
? ? */
? ? function setPrices(uint256 newSellPrice, uint256 newBuyPrice) onlyOwner public {
? ? ? ? sellPrice = newSellPrice;
? ? ? ? buyPrice = newBuyPrice;
? ? }
? ? /**
? ? * 使用以太幣購買代幣
? ? */
? ? 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)試通過
Go-Ethereum 1.7.2 結(jié)合 Mist 0.9.2 實(shí)現(xiàn)代幣智能合約的實(shí)例
以太坊使用數(shù)字貨幣(通證)完成去中心化投票DApp
基于以太坊發(fā)布屬于自己的數(shù)字貨幣(代幣)完整版