今天就跟大家聊聊有關(guān)怎樣理解eos區(qū)塊鏈的eosio.token合約,可能很多人都不太了解,為了讓大家更加了解,小編給大家總結(jié)了以下內(nèi)容,希望大家根據(jù)這篇文章可以有所收獲。
讓客戶滿意是我們工作的目標(biāo),不斷超越客戶的期望值來自于我們對(duì)這個(gè)行業(yè)的熱愛。我們立志把好的技術(shù)通過有效、簡(jiǎn)單的方式提供給客戶,將通過不懈努力成為客戶在信息化領(lǐng)域值得信任、有價(jià)值的長(zhǎng)期合作伙伴,公司提供的服務(wù)項(xiàng)目有:空間域名、虛擬主機(jī)、營(yíng)銷軟件、網(wǎng)站建設(shè)、都蘭網(wǎng)站維護(hù)、網(wǎng)站推廣。
我必須承認(rèn),學(xué)習(xí)eosio一直沒有閑庭信步的感覺,我可以看到為什么很多人說它有一個(gè)陡峭的學(xué)習(xí)曲線。隨著eosio軟件繼續(xù)經(jīng)歷大量快速發(fā)展,文檔數(shù)量有限,很少有工作實(shí)例可供參考。我已經(jīng)被困了好幾次,也希望幫助改善下一個(gè)開發(fā)人員的體驗(yàn)。
eosio.token合約允許創(chuàng)建許多不同的代幣。這使任何人都能夠創(chuàng)建和發(fā)送代幣。每個(gè)代幣必須由issuer
帳戶發(fā)行。由于帳戶可以包含多方,因此你可以使用具有所有者和活動(dòng)權(quán)限的普通帳戶或自定義配置帳戶來創(chuàng)建和管理代幣。每個(gè)代幣都是asset
類型,如下所示:
1000000000.0000 SYS 1.0000 SYMBOL 0.10 SYS
asset
類型是一個(gè)數(shù)字(如果我沒記錯(cuò)的話可以達(dá)到18位小數(shù))和一個(gè)可以在1-7個(gè)大寫字母之間的符號(hào)。此合約有三個(gè)操作可用于與之交互。它們是:創(chuàng)建,發(fā)布和轉(zhuǎn)賬。
創(chuàng)建用于定義新代幣的特征。這包括代幣asset
符號(hào),最大供應(yīng)量以及允許發(fā)出代幣的帳戶。創(chuàng)建還會(huì)將新代幣配置保留在區(qū)塊鏈上。這意味著新代幣配置的存儲(chǔ)必須由某人放置。正如你稍后將看到的,部署此合約的帳戶(在我們的案例中為'eosio.token')也將支付代幣配置存儲(chǔ)。
發(fā)布用于增加代幣的有效供應(yīng)??梢猿掷m(xù)發(fā)出代幣,直到達(dá)到最大供應(yīng)量。在代幣創(chuàng)建期間定義的issuer
必須批準(zhǔn)此操作才能使其成功。
轉(zhuǎn)賬讓一個(gè)帳戶將代幣轉(zhuǎn)移到另一個(gè)帳戶。
你應(yīng)該知道的第一件事是每個(gè)eosio智能合約都屬于一個(gè)eosio帳戶。合約基本上是其他帳戶可以與之交互的對(duì)象。合約包含在區(qū)塊鏈上執(zhí)行代碼的操作actions
。合約可以直接訪問區(qū)塊鏈上的存儲(chǔ),刪除和更新數(shù)據(jù)。
將一個(gè)action推送到合約需要至少一個(gè)帳戶的授權(quán)。根據(jù)合約的復(fù)雜性,可能需要進(jìn)一步的帳戶和權(quán)限。帳戶可以由基于權(quán)限的配置中設(shè)置的單個(gè)或多個(gè)個(gè)人組成。智能合約只能由一個(gè)帳戶運(yùn)行,而一個(gè)帳戶只能擁有一個(gè)智能合約。最佳做法是為帳戶和合約提供相同(小寫)的名稱。
在你與eosio.token合約進(jìn)行交互之前,你需要?jiǎng)?chuàng)建一個(gè)具有相同名稱的帳戶,并將合約部署到該帳戶。
首先創(chuàng)建一個(gè)帳戶
$cleos create account eosio eosio.token
然后編譯合約
$cd eos/contract/eosio.token $eosiocpp -o eosio.token.wast eosio.token.cpp
最后將合約部署到帳戶上
$cleos set contract eosio.token ../eosio.token
你可以驗(yàn)證合約是否已部署
$cleos get code eosio.token
合約分為兩個(gè)文件eosio.token.cpp
和eosio.token.hpp
。.hpp
文件定義合約類,操作和表,而.cpp
文件實(shí)現(xiàn)操作邏輯。讓我們首先看一下將用于實(shí)例化合約對(duì)象的合約類。(我從eosio.token.hpp
中刪除了一些遺留代碼)
/** * @file * @copyright defined in eos/LICENSE.txt */ #pragma once #include#include #include namespace eosiosystem { class system_contract; } namespace eosio { using std::string; class token : public contract { public: token( account_name self ):contract(self){} void create( account_name issuer, asset maximum_supply); void issue( account_name to, asset quantity, string memo ); void transfer( account_name from, account_name to, asset quantity, string memo ); private: friend eosiosystem::system_contract; inline asset get_supply( symbol_name sym )const; inline asset get_balance( account_name owner, symbol_name sym )const; struct account { asset balance; uint64_t primary_key()const { return balance.symbol.name(); } }; struct currency_stats { asset supply; asset max_supply; account_name issuer; uint64_t primary_key()const { return supply.symbol.name(); } }; typedef eosio::multi_index accounts; typedef eosio::multi_index stats; void sub_balance( account_name owner, asset value ); void add_balance( account_name owner, asset value, account_name ram_payer ); }; asset token::get_supply( symbol_name sym )const { stats statstable( _self, sym ); const auto& st = statstable.get( sym ); return st.supply; } asset token::get_balance( account_name owner, symbol_name sym )const { accounts accountstable( _self, owner ); const auto& ac = accountstable.get( sym ); return ac.balance; } } /// namespace eosio
構(gòu)造函數(shù)和操作被定義為公共成員函數(shù)。構(gòu)造函數(shù)采用帳戶名稱(將是部署合約的帳戶,也就是eosio.token)并將其設(shè)置為contract變量。請(qǐng)注意,此類繼承自eosio::contract
。
表和helper函數(shù)作為私有成員提供。兩個(gè)內(nèi)聯(lián)函數(shù)在底部定義但從未使用過。這給我們留下了重要的函數(shù)sub_balance()
和add_balance()
。這些將由轉(zhuǎn)移操作調(diào)用。
定義的兩個(gè)表是accounts
和stat
。accounts
表由不同的account
對(duì)象組成,每個(gè)account
對(duì)象持有不同代幣的余額。stat
表由持有供應(yīng),max_supply
和發(fā)行者的currency_stats
對(duì)象(由struct currency_stats
定義)組成。在繼續(xù)之前,重要的是要知道該合約將數(shù)據(jù)保存到兩個(gè)不同的范圍。accounts
表的范圍限定為eosio帳戶,stat
表的范圍限定為代幣符號(hào)名稱。
根據(jù)eosio::multi_index
定義,code
是具有寫權(quán)限的帳戶的名稱,scope
是存儲(chǔ)數(shù)據(jù)的帳戶。
范圍本質(zhì)上是一種在合約中劃分?jǐn)?shù)據(jù)的方法,以便只能在定義的空間內(nèi)訪問。在代幣合約中,每個(gè)eosio帳戶都用作accounts
表的范圍。accounts
表是一個(gè)包含多個(gè)account
對(duì)象的多索引容器。每個(gè)account
對(duì)象都由其代幣符號(hào)編制索引,并包含代幣余額。使用其范圍查詢用戶的accounts
表時(shí),將返回用戶具有現(xiàn)有余額的所有代幣的列表。
這是我如何想象它。
在上圖中,有一個(gè)名為tom的eosio帳戶,他有自己的范圍。在他的范圍內(nèi)是一個(gè)名為accounts
的表。在該表中是一個(gè)單獨(dú)的account
對(duì)象,用于他持有的每個(gè)代幣,SYS
和EOS
。
還有一個(gè)名為stat
的第二個(gè)表。此表將包含現(xiàn)有代幣的狀態(tài)。新標(biāo)記在其自己的符號(hào)名稱范圍內(nèi)創(chuàng)建。范圍內(nèi)是一個(gè)包含currency_stats
對(duì)象的stat
表。與包含許多不同account
對(duì)象的accounts
表不同,stat
表僅包含給定標(biāo)記符號(hào)的單個(gè)currency_stats
對(duì)象。
操作在.cpp
文件中實(shí)現(xiàn)。要?jiǎng)?chuàng)建新代幣,必須發(fā)送創(chuàng)建操作。Create
有兩個(gè)參數(shù):發(fā)行者,以及新代幣的最大供應(yīng)量。issuer
是唯一允許增加新代幣供應(yīng)的人。issuer
不能超過最高供應(yīng)量發(fā)行。
第一行代碼只需要合約帳戶本身的授權(quán)。這可以在推動(dòng)操作時(shí)使用命令行標(biāo)志-p eosio.token
給出。
接下來的幾行提取傳入的maximum_supply
資產(chǎn)的符號(hào)并執(zhí)行一些錯(cuò)誤處理。如果任何eosio_assert
失敗,那么所有代碼都將被回滾,并且交易不會(huì)被推送到區(qū)塊鏈。
一個(gè)stat
表使用符號(hào)名稱(標(biāo)記符號(hào))作為其范圍構(gòu)造為statstable
。代碼檢查代幣是否已存在。如果沒有,則創(chuàng)建新代幣狀態(tài)并將其保存到區(qū)塊鏈中。emplace
函數(shù)中的第一個(gè)參數(shù)_self
意味著此合約帳戶eosio.token
將支付投注存儲(chǔ)。
請(qǐng)注意,保存supply
的符號(hào),因?yàn)樗米鞫ㄎ槐硇械逆I,但供應(yīng)量尚未發(fā)出。
你現(xiàn)在可以執(zhí)行下一個(gè)操作,發(fā)布。發(fā)布將采用將收到已發(fā)行代幣的帳戶,發(fā)出的代幣數(shù)量和備忘錄。發(fā)布操作在一個(gè)中執(zhí)行兩個(gè)操作,因?yàn)樗鼘⑿薷膭?chuàng)建的代幣供應(yīng)并調(diào)用轉(zhuǎn)賬操作以發(fā)送已發(fā)布的代幣。同樣,前幾行提取代幣符號(hào)并執(zhí)行錯(cuò)誤檢查。
以下代碼部分將使用符號(hào)名稱作為范圍構(gòu)造stat
表。這用作查找先前使用create action
創(chuàng)建的代幣的鍵。
請(qǐng)注意,從statstable.find()
返回的existing currency_stat
是一個(gè)指向找到的對(duì)象的迭代器。為簡(jiǎn)潔起見,聲明了一個(gè)名為st
的新變量,并將其設(shè)置為existing
迭代器指向的實(shí)際對(duì)象。這讓我們可以使用.
運(yùn)算符訪問成員變量而不是指針表示法->
。
創(chuàng)建代幣的issuer
者需要簽署此交易,并執(zhí)行更多錯(cuò)誤處理。
最后,修改現(xiàn)有代幣的currency_stats st
,并將已發(fā)放的quantity
添加到supply
。issuer
也將此supply
添加到他們的余額中,以便初始供應(yīng)可以追溯到他們的帳戶。
緊接著,通過SEND_INLINE_ACTION()
調(diào)用transfer
函數(shù),這會(huì)將資金進(jìn)行轉(zhuǎn)移。論點(diǎn)如下:
1.*this
是行動(dòng)所屬的合約代碼。
2.transfer
操作的名稱。
3.{st.issuer, N(active)}
操作所需的權(quán)限。
4.{st.issuer, to, quantity, memo}
操作本身的參數(shù)。
這將我們帶到最后的轉(zhuǎn)賬操作。轉(zhuǎn)賬操作將從from
,to
,quantity
和memo
獲取四個(gè)輸入?yún)?shù)。from
是誰將發(fā)送代幣,因此quantity
將從他們的余額中減去。to
是誰將收到代幣,因此quantity
將被添加到他們的余額。quantity
是要發(fā)送的代幣數(shù)量,memo
是一個(gè)可以與交易一起發(fā)送的字符串。memo
未在本合約中使用或存儲(chǔ)。
該操作首先要求from
accounts帳戶權(quán)限并對(duì)from
和to
帳戶執(zhí)行發(fā)布處理。該符號(hào)從quantity
提取并用于獲取代幣的currency_stats
。
require_recipient()
函數(shù)將在操作完成時(shí)通知發(fā)送方和接收方。
完成更多發(fā)布處理,最后調(diào)用兩個(gè)私有函數(shù)sub_balance()
和add_balance()
以從發(fā)送add_balance()
減去代幣余額并增加接收方的代幣余額。
這是完整的'eosio.token.cpp'文件。
/** * @file * @copyright defined in eos/LICENSE.txt */ #include "eosio.token.hpp" namespace eosio { void token::create( account_name issuer, asset maximum_supply ) { require_auth( _self ); auto sym = maximum_supply.symbol; eosio_assert( sym.is_valid(), "invalid symbol name" ); eosio_assert( maximum_supply.is_valid(), "invalid supply"); eosio_assert( maximum_supply.amount > 0, "max-supply must be positive"); stats statstable( _self, sym.name() ); auto existing = statstable.find( sym.name() ); eosio_assert( existing == statstable.end(), "token with symbol already exists" ); statstable.emplace( _self, [&]( auto& s ) { s.supply.symbol = maximum_supply.symbol; s.max_supply = maximum_supply; s.issuer = issuer; }); } void token::issue( account_name to, asset quantity, string memo ) { auto sym = quantity.symbol; eosio_assert( sym.is_valid(), "invalid symbol name" ); eosio_assert( memo.size() <= 256, "memo has more than 256 bytes" ); auto sym_name = sym.name(); stats statstable( _self, sym_name ); auto existing = statstable.find( sym_name ); eosio_assert( existing != statstable.end(), "token with symbol does not exist, create token before issue" ); const auto& st = *existing; require_auth( st.issuer ); eosio_assert( quantity.is_valid(), "invalid quantity" ); eosio_assert( quantity.amount > 0, "must issue positive quantity" ); eosio_assert( quantity.symbol == st.supply.symbol, "symbol precision mismatch" ); eosio_assert( quantity.amount <= st.max_supply.amount - st.supply.amount, "quantity exceeds available supply"); statstable.modify( st, 0, [&]( auto& s ) { s.supply += quantity; }); add_balance( st.issuer, quantity, st.issuer ); if( to != st.issuer ) { SEND_INLINE_ACTION( *this, transfer, {st.issuer,N(active)}, {st.issuer, to, quantity, memo} ); } } void token::transfer( account_name from, account_name to, asset quantity, string memo ) { eosio_assert( from != to, "cannot transfer to self" ); require_auth( from ); eosio_assert( is_account( to ), "to account does not exist"); auto sym = quantity.symbol.name(); stats statstable( _self, sym ); const auto& st = statstable.get( sym ); require_recipient( from ); require_recipient( to ); eosio_assert( quantity.is_valid(), "invalid quantity" ); eosio_assert( quantity.amount > 0, "must transfer positive quantity" ); eosio_assert( quantity.symbol == st.supply.symbol, "symbol precision mismatch" ); eosio_assert( memo.size() <= 256, "memo has more than 256 bytes" ); sub_balance( from, quantity ); add_balance( to, quantity, from ); } void token::sub_balance( account_name owner, asset value ) { accounts from_acnts( _self, owner ); const auto& from = from_acnts.get( value.symbol.name(), "no balance object found" ); eosio_assert( from.balance.amount >= value.amount, "overdrawn balance" ); if( from.balance.amount == value.amount ) { from_acnts.erase( from ); } else { from_acnts.modify( from, owner, [&]( auto& a ) { a.balance -= value; }); } } void token::add_balance( account_name owner, asset value, account_name ram_payer ) { accounts to_acnts( _self, owner ); auto to = to_acnts.find( value.symbol.name() ); if( to == to_acnts.end() ) { to_acnts.emplace( ram_payer, [&]( auto& a ){ a.balance = value; }); } else { to_acnts.modify( to, 0, [&]( auto& a ) { a.balance += value; }); } } } /// namespace eosio EOSIO_ABI( eosio::token, (create)(issue)(transfer) )
示例命令:
$cleos push action eosio.token create '["usera","21000000.0000 DEMO"]' -p eosio.token usera $cleos push action eosio.token issue '["usera","21000000.0000 DEMO","issuance"]' -p usera $cleos push action eosio.token tranfser '["usera","userb","1000000.0000 DEMO","here you go"]' -p usera
表命令:
$cleos get table eosio.token DEMO stat { "rows": [{ "supply": "21000000.0000 DEMO" "max_supply": "2100000000.0000 DEMO" "issuer": "usera" } ], "more": false } $cleos get table eosio.token usera accounts { "rows": [{ "balance": "20000000.0000 DEMO" } ], "more": false } $cleos get table eosio.token userb accounts { "rows": [{ "balance": "10000000.0000 DEMO" } ], "more": false }
注意:本文是在Dawn4.1代碼發(fā)布時(shí)編寫的。
======================================================================
分享一些以太坊、EOS、比特幣等區(qū)塊鏈相關(guān)的交互式在線編程實(shí)戰(zhàn)教程:
EOS教程,本課程幫助你快速入門EOS區(qū)塊鏈去中心化應(yīng)用的開發(fā),內(nèi)容涵蓋EOS工具鏈、賬戶與錢包、發(fā)行代幣、智能合約開發(fā)與部署、使用代碼與智能合約交互等核心知識(shí)點(diǎn),最后綜合運(yùn)用各知識(shí)點(diǎn)完成一個(gè)便簽DApp的開發(fā)。
java以太坊開發(fā)教程,主要是針對(duì)java和android程序員進(jìn)行區(qū)塊鏈以太坊開發(fā)的web3j詳解。
python以太坊,主要是針對(duì)python工程師使用web3.py進(jìn)行區(qū)塊鏈以太坊開發(fā)的詳解。
php以太坊,主要是介紹使用php進(jìn)行智能合約開發(fā)交互,進(jìn)行賬號(hào)創(chuàng)建、交易、轉(zhuǎn)賬、代幣開發(fā)以及過濾器和交易等內(nèi)容。
以太坊入門教程,主要介紹智能合約與dapp應(yīng)用開發(fā),適合入門。
以太坊開發(fā)進(jìn)階教程,主要是介紹使用node.js、MongoDB、區(qū)塊鏈、ipfs實(shí)現(xiàn)去中心化電商DApp實(shí)戰(zhàn),適合進(jìn)階。
C#以太坊,主要講解如何使用C#開發(fā)基于.Net的以太坊應(yīng)用,包括賬戶管理、狀態(tài)與交易、智能合約開發(fā)與交互、過濾器和交易等。
java比特幣開發(fā)教程,本課程面向初學(xué)者,內(nèi)容即涵蓋比特幣的核心概念,例如區(qū)塊鏈存儲(chǔ)、去中心化共識(shí)機(jī)制、密鑰與腳本、交易與UTXO等,同時(shí)也詳細(xì)講解如何在Java代碼中集成比特幣支持功能,例如創(chuàng)建地址、管理錢包、構(gòu)造裸交易等,是Java工程師不可多得的比特幣開發(fā)學(xué)習(xí)課程。
php比特幣開發(fā)教程,本課程面向初學(xué)者,內(nèi)容即涵蓋比特幣的核心概念,例如區(qū)塊鏈存儲(chǔ)、去中心化共識(shí)機(jī)制、密鑰與腳本、交易與UTXO等,同時(shí)也詳細(xì)講解如何在Php代碼中集成比特幣支持功能,例如創(chuàng)建地址、管理錢包、構(gòu)造裸交易等,是Php工程師不可多得的比特幣開發(fā)學(xué)習(xí)課程。
tendermint區(qū)塊鏈開發(fā)詳解,本課程適合希望使用tendermint進(jìn)行區(qū)塊鏈開發(fā)的工程師,課程內(nèi)容即包括tendermint應(yīng)用開發(fā)模型中的核心概念,例如ABCI接口、默克爾樹、多版本狀態(tài)庫等,也包括代幣發(fā)行等豐富的實(shí)操代碼,是go語言工程師快速入門區(qū)塊鏈開發(fā)的最佳選擇。
看完上述內(nèi)容,你們對(duì)怎樣理解eos區(qū)塊鏈的eosio.token合約有進(jìn)一步的了解嗎?如果還想了解更多知識(shí)或者相關(guān)內(nèi)容,請(qǐng)關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道,感謝大家的支持。