原文連接:醒者呆的博客園,www.cnblogs.com/Evsward/p/e…html
EOS智能合約中包含一個exchange合約,它支持用戶建立一筆交易,是任何兩個基本貨幣類型之間的交易。這個合約的做用是跨不一樣幣種(都是EOS上的標準貨幣類型)的,經過各自與EOS主鏈價值進行錨定,而後再相互發起交易兌換。要搞清楚的是,這與區塊鏈「傳統的」交易所並不同,那個主要是集中在交易撮合上面,並且必須是同一幣種。java
關鍵字:EOS token 經濟模型,exchange,Pegged Currency,LTV,cmake,跨token交易,ubuntu編譯boost庫,通證模型,抵押資產,token價值轉換c++
上面一直提到標準貨幣(standard currency),在EOS.io中也針對這一標準貨幣的設計給出了官方文檔,本章先來弄清楚標準貨幣的概念,而後再繼續分析exchange。算法
文章的名字叫《Pegged Derivative Currency Design》數據庫
Pegged Currency的含義是什麼?
複製代碼
Currency pegging是用來固定匯率的一種方式,經過匹配當前貨幣與其餘貨幣的價值錨定,或者其餘價值度量方式,例如黃金和白銀。因此Pegged Currency能夠理解爲匯率穩定的貨幣。express
因此,這篇文章的題目能夠翻譯爲:一種價值穩定的衍生貨幣設計。編程
目前市面已有的Pegged Derivative 貨幣,例如BitUSD,比特美圓,它是一種以加密貨幣做爲抵押。發行人是短線持有美圓而額外長地持有加密貨幣。而購買者是單純地長期持有美圓。ubuntu
比特股BitShares創造了第一個可行的價值穩定的資產系統:緩存
容許任何人得到一個最小的抵押情況是,公佈抵押物和得到的BitUSD的價值比率在最小的1.5:1(抵押物:負債率)。
複製代碼
最少的抵押情況下,要強迫BitUSD持有人在任何市場價格下跌超過美圓幾個百分點如下的時候的流動性(若是BitUSD持有人選擇使用強制清算是不容許的)。換句話說,就是在當前貨幣下跌的時候,也要保證貨幣流通性,這是爲了貨幣情況健康運營而考慮。bash
爲了防止價格補償(直接經過增發和賣出來控制價格)的濫用,全部的強制清算會被推遲。當發生「黑天鵝」事件(極小可能性發生,但實際上卻發生了)的時候,全部的短線會經過價格補償擁有他們本身的清算情況,而全部的BitUSD的持有者只能承諾一個固定的贖回率(清算時固定一個贖回率)。
這種設計的問題體如今:
這是一種讓短線持股人經過提供一種高流通性的價值穩定的資產來穩訂貨幣資產。他們會經過鼓勵人們交易他們的穩值資產來獲益,賺取交易費而不是在投機市場尋求高槓杆。也會經過賺取短線持股的利息。
一個初始用戶存儲了一個可擔保貨幣(C)到一個智能合約,而且提供一個初始化價格補償。經過C:D等於1.5:1的價格補償率發行一個新的負債token(D),這個token會被存儲在Bancor市場製造商。
Bancor是爲以太坊的代幣的價值判斷以及流通機制。經過智能合約,可將這些代幣做爲儲備金,讓任何人隨時隨地經過智能合約進行快速兌換,銷燬代幣,提升代幣流通性。
複製代碼
這樣一來,由於沒有D token被賣出,因此市場製造商是0槓桿。那個初始用戶也會收到交換token(E)從市場製造商那裏。
咱們繼續,人們如今能夠購買E或者D token,Bancor算法會提供基於C,E,D之間的流通性。因爲市場製造商的收費,E的價值將隨着C而增加。
C = 智能代幣或者母貨幣儲備
D或E = 獎勵代幣(發放給初期持有人,以及社區貢獻者)
抵押率C:D = 價值C(抵押物)借款D(負債)比(反過來就是LTV,loan to value)
複製代碼
咱們作了這麼多工做,其實目的就是要保障D這種token(token自己就是衍生貨幣)是符合Pegged Currency的設定。最直接的指標就是與美圓價值(C就能夠是這個角色)的錨定浮動範圍,要儘量小,這個範圍的浮動要小到讓更多的人(套匯者)願意持有和交易D token。下面有幾種可能性:
市場體量 = 聯結者體量(Bancor) 贖回價格:在到期以前,發行人能夠回購持有者的token。
基於上面標準貨幣體系,咱們能夠看到在EOS上面的token的經濟模型,這是一個頗有競爭力的模型,能夠保證每一個token的價值穩定,而不是狂漲狂跌,真正使EOS上的經濟生態健康穩定運轉起來。下面來研究exchange智能合約的主要功能。
首先來看CMake設置,上文《【精解】EOS智能合約演練》中也有CMake的應用,但並無搞太清楚,這裏在討論exchange的CMakeLists配置以前,咱們先來搞定cmake自己。
cmake
CMake於C++ 相似maven於java的存在,它能夠用來對軟件進行構建、測試以及打包等工做。咱們在研究C++ 項目的時候,CMake是很好的構建工具,必定要熟悉掌握。
複製代碼
正如maven的配置文件主要是經過pom.xml同樣,CMake的工做是經過CMakeLists.txt文件來描述的。因此掌握CMakeLists.txt文件的配置方法是必要的。
咱們在IDE中,也能夠像直接經過項目中的pom文件導入maven項目那樣,經過項目中的CMakelists.txt文件導入CMake項目。
像以上這種設置命令有不少,咱們能夠參照《CMake官方文檔:命令解釋》來查閱相關命令的含義以及使用。
exchange cmake
file(GLOB ABI_FILES "*.abi")
add_wast_executable(TARGET exchange
INCLUDE_FOLDERS "${STANDARD_INCLUDE_FOLDERS}"
LIBRARIES libc++ libc eosiolib
DESTINATION_FOLDER ${CMAKE_CURRENT_BINARY_DIR}
)
configure_file("${ABI_FILES}" "${CMAKE_CURRENT_BINARY_DIR}" COPYONLY)
add_dependencies( exchange currency )
add_executable(test_exchange test_exchange.cpp )
#bfp/lib/pack.c bfp/lib/posit.cpp bfp/lib/util.c bfp/lib/op2.c)
target_link_libraries( test_exchange fc )
target_include_directories( test_exchange PUBLIC fixed_point/include )
複製代碼
咱們在源碼位置eos/CMakeModules中能夠找到wasm.cmake文件,進去之後能夠發現
macro(add_wast_executable)
自定義module也是以宏(命令集對外爲單一命令)的形式(Excel中我以前寫過宏腳本,也是同一個詞macro)。這一段add_wast_executable內容不少,我就不粘貼了,主要內容是爲了wasm環境構建代碼,包括對打包內容的描述,對狀態的判斷處理等各類命令的集合,其中又包含了不少module宏。
abi文件是經過eosiocpp工具經過exchange.cpp生成的,具體可參照《EOS智能合約演練》。
從這裏開始咱們來詳細分析exchange合約的源碼內容,exchange.cpp須要引用exchange_accounts, exchange_state以及market_state這三個庫。其中market_state又依賴兩外兩個庫,所以咱們先從比較獨立的exchange_accounts入手。
exchange_accounts.hpp
#pragma once
#include <eosiolib/asset.hpp>
#include <eosiolib/multi_index.hpp>
namespace eosio {
using boost::container::flat_map;// 至關於java中的import,下面能夠直接使用flat_map方法。
/**
* 每一個用戶都有他們本身的帳戶,而且這個帳戶是帶有exchange合約的。這可讓他們保持跟蹤一個用戶是如何抵押各類擴展資產類型的。假定存儲一個獨立的flat_map,包含一個特定用戶的全部餘額,這個用戶比起打破使用擴展標識來排序的多重索引表,將更加實際的
*/
struct exaccount {
account_name owner;// uint64_t類型,64位無符號整型
flat_map<extended_symbol, int64_t> balances;// extended_symbol是asset.hpp中定義的
uint64_t primary_key() const { return owner; }// 結構體包含一個primary_key方法是不可變的,const,實現也有了,直接是返回owner。
EOSLIB_SERIALIZE( exaccount, (owner)(balances) )// EOSLIB_SERIALIZE這是一種自定義的模板,是一種反射機制,能夠給結構體賦值,第一個參數爲結構體名字,後面的參數用括號分別括起來,傳入當前兩個成員變量。
};
typedef eosio::multi_index<N(exaccounts), exaccount> exaccounts;// multi_index是一個類,這行定義了一個變量exaccounts,它的類型是一種多重索引。
/**
* 提供一個抽象接口,爲用戶的餘額排序。這個類緩存了數據表,以提供高效地多重訪問。
*/
struct exchange_accounts {
exchange_accounts( account_name code ):_this_contract(code){}// 給私有成員賦值
void adjust_balance( account_name owner, extended_asset delta, const string& reason = string() );//調整餘額,傳入owner、擴展資產,reason。exchange\_accounts.cpp會實現該函數。
private:
account_name _this_contract;// 私有成員 \_this\_contract
/**
* 保留一個緩存,用來存儲咱們訪問的全部用戶表
*/
flat_map<account_name, exaccounts> exaccounts_cache;// flat_map類型的緩存exaccounts_cache,存儲的是帳戶名和以上結構體exaccounts。
};
} /// namespace eosio
複製代碼
multi_index這裏再簡單介紹一下。它的模板定義是
template<uint64_t TableName, typename T, typename... Indices>
泛型中第一個參數是表名,第二個是多重索引。
N函數的源碼:
/**
* @brief 用來生成一個編譯時間,它是64位無符號整型。傳入的參數X是一個base32編碼的字符串的解釋。
* @ingroup types
*/
#define N(X) ::eosio::string_to_name(#X)
複製代碼
可參考文章《EOS技術研究:合約與數據庫交互》,下面來看一下exchange_accounts.cpp源碼:
#include <exchange/exchange_accounts.hpp>
namespace eosio {
void exchange_accounts::adjust_balance( account_name owner, extended_asset delta, const string& reason ) {
(void)reason;// reason當作一個備註,不可修改的。
auto table = exaccounts_cache.find( owner );//經過account\_name查找到對應的exaccount結構體對象數據。
if( table == exaccounts_cache.end() ) {// 若是這個數據是最後一個,則將當前數據從新包裝放入exaccounts_cache,同時將exaccounts_cache第一位的數據從新賦值給table
table = exaccounts_cache.emplace( owner, exaccounts(_this_contract, owner ) ).first;
}
auto useraccounts = table->second.find( owner );//table如今有值了,在table下一個位置查找owner
if( useraccounts == table->second.end() ) {// 若是這個用戶是table下一個位置的結尾數據,則將owner從新組裝數據放入table
table->second.emplace( owner, [&]( auto& exa ){
exa.owner = owner;
exa.balances[delta.get_extended_symbol()] = delta.amount;
eosio_assert( delta.amount >= 0, "overdrawn balance 1" );//斷言,當extended_assert資產的數目小於0時,打印日誌:透支餘額1
});
} else {// 若是該用戶不是table下一個位置的結尾數據,則修改以該用戶爲key的數據,
table->second.modify( useraccounts, 0, [&]( auto& exa ) {
const auto& b = exa.balances[delta.get_extended_symbol()] += delta.amount;// 擴展標識的餘額加上extended_assert資產的數目爲b
eosio_assert( b >= 0, "overdrawn balance 2" );// 斷言,當b小於0時,打印日誌:透支餘額2
});
}
}
} /// namespace eosio
複製代碼
它實現了adjust_balance函數。這個函數主要實現了對帳戶數據的管理,餘額的判斷與處理。
exchange_state庫的源碼我就不張貼了,這裏進行一個總結:
下面是connector的源碼部分:
struct connector {
extended_asset balance;// 餘額
uint32_t weight = 500;// 權重
margin_state peer_margin; /// peer_connector 抵押借貸餘額,margin_state類型
EOSLIB_SERIALIZE( connector, (balance)(weight)(peer_margin) )仍是那個初始化工具。
};
複製代碼
exchange_state庫中最重要的函數就是上面這幾個轉換函數,掌握這些函數都能幹哪些事,將來咱們能夠直接測試調用或者在其餘源碼中出現繼續分析。
這是基於以上exchange_accounts以及exchange_state兩個庫的庫,它的內容也不少,不適宜所有粘貼出來。
這是整個exchange合約的主庫(一般我會將一個名字的頭文件加源文件合併稱爲一個庫,這也是C++ 的命名習慣)。
exchange.hpp
頭文件,主要聲明瞭一個類exchange,這裏麪包含了三個私有成員,以及七個公有函數,還有三個公有結構體,下面貼一下源碼吧:
#include <eosiolib/types.hpp>
#include <eosiolib/currency.hpp>
#include <boost/container/flat_map.hpp>
#include <cmath>
#include <exchange/market_state.hpp>
namespace eosio {
/**
* 這個合約可讓用戶在任意一對標準貨幣類型之間建立一個exchange,這個exchange是基於一個在購買方和發行方雙邊的價值等額的條件下而建立的。爲了預防舍入偏差,初始化金額應該包含大量的base以及quote貨幣的數量,而且exchange 共享應該在最大初始化金額的100倍的數量。用戶在他們經過exchange交易前,必須先存入資金到exchange。每次一個exchange建立一個新的貨幣時,相應的交易市場製造商也會被建立。貨幣供應以及貨幣符號必須是惟一的而且它使用currency合約的表來管理。
*/
class exchange {
private:
account_name _this_contract;// 私有,帳戶名
currency _excurrencies;// 貨幣
exchange_accounts _accounts;// exchange的帳戶
public:
exchange( account_name self )
:_this_contract(self),
_excurrencies(self),
_accounts(self)
{}
// 建立
void createx( account_name creator,
asset initial_supply,
uint32_t fee,
extended_asset base_deposit,
extended_asset quote_deposit
);
// 訂金
void deposit( account_name from, extended_asset quantity );
// 提現
void withdraw( account_name from, extended_asset quantity );
// 借出
void lend( account_name lender, symbol_type market, extended_asset quantity );
// 不借?
void unlend(
account_name lender,
symbol_type market,
double interest_shares,
extended_symbol interest_symbol
);
// 邊緣覆蓋結構體
struct covermargin {
account_name borrower;
symbol_type market;
extended_asset cover_amount;
};
// 上側邊緣
struct upmargin {
account_name borrower;
symbol_type market;
extended_asset delta_borrow;
extended_asset delta_collateral;
};
// 交易結構體
struct trade {
account_name seller;
symbol_type market;
extended_asset sell;
extended_asset min_receive;
uint32_t expire = 0;
uint8_t fill_or_kill = true;
};
// 函數名根據參數列表方法重載,在xxx上執行exchange
void on( const trade& t );
void on( const upmargin& b );
void on( const covermargin& b );
void on( const currency::transfer& t, account_name code );
// 應用
void apply( account_name contract, account_name act );
};
} // namespace eosio
複製代碼
該源文件中實現了以上頭文件中定義的全部公有方法。
先定義兩個標準貨幣base和quote,他們都是exchange_state類型:
exchange_state state;
state.supply = 100000000000ll;// 發行量
//state.base.weight = state.total_weight / 2.;
state.base.balance.amount = 100000000;
state.base.balance.symbol = "USD";
state.base.weight = .49;
//state.quote.weight = state.total_weight / 2.;
state.quote.balance.amount = state.base.balance.amount;
state.quote.balance.symbol = "BTC";
state.quote.weight = .51;
print_state( state );
複製代碼
插曲:ubuntu編譯boost庫
複製代碼
首先在boost官網下載最新庫文件,目前我下載的版本是boost_1_67_0.tar.bz2。
而後,咱們再打開CLion,CMake自動編譯項目eos,會發現console中已經顯式編譯成功的字樣。
接下來繼續咱們的測試。直接run 主函數,首先打印出來的是"USD"和"BTC"的發行信息,
-----------------------------
supply: 1e+11
base: 1e+08 USD
quote: 1e+08 BTC
-----------------------------
複製代碼
能夠看到,這與代碼中定義的總髮行量以及包含的兩種符號類型的token的各自發行量,都是準確的。
exchange_state是在測試類中咱們自定義的數字資產類型,下面是它的結構:
struct exchange_state {
token_type supply;// 發行量
symbol_type symbol = exchange_symbol;// exchange符號
// 兩個鏈接器base和quote
connector base;
connector quote;
// 交易
void transfer( account_name user, asset q ) {
output[balance_key{user,q.symbol}] += q.amount;
}
map<balance_key, token_type> output;
vector<margin> margins;
};
複製代碼
exchange_state數字資產中,包含一個總髮行量,兩個成員資產base和quote,他們是connector類型,這個類型也是自定義的(與上面介紹的源碼稍有不一樣,稍後在測試完成之後會總結他們的區別),交易函數以及一個自定義集合output和margins,下面來看connector的定義:
struct connector {
asset balance; // asset資產類型
real_type weight = 0.5;
token_type total_lent; /// 發行商從用戶的貸款
token_type total_borrowed; /// 發行商借給用戶
token_type total_available_to_lend; /// 可借出的有效數量
token_type interest_pool; /// 利息池,是所得到的總利息,但不必定每一個用戶均可以申請使用
// 如下三個方法都在本文件下被實現了。
void borrow( exchange_state& ex, const asset& amount_to_borrow );
asset convert_to_exchange( exchange_state& ex, const asset& input );
asset convert_from_exchange( exchange_state& ex, const asset& input );
};
複製代碼
這個connector有一個餘額,一個權重(可理解爲佔有exchange_state數字資產的比例),它的一些銀行資產功能屬性,貸款拆借利息等,以及connector自己做爲資產能夠與其餘exchange_state數字資產進行轉換,拆借等功能。餘額成員是asset資產類型,這個類型也是一個自定義結構體:
struct asset {
token_type amount;
symbol_type symbol;
};
複製代碼
它具有一個總數量和符號兩個成員。因此以上咱們給exchange_state數字資產定義了兩個connector,「BTC」和「USD」以及它們各自的發行量,正是採用這個asset的結構進行賦值的。
打印出state內容之後,顯示的是兩種token"USD"和"BTC"的發行信息,接下來,咱們利用exchange中的一些函數功能進行兩種token之間的轉換及交易。
auto new_state = convert(state, "dan", asset{100, "USD"}, asset{0, "BTC"});
print_state(new_state);
複製代碼
看一下這裏面的convert函數的聲明:
/**
* 經過給出的一個當前state,計算出一個新的state返回。
*/
exchange_state convert( const exchange_state& current,// 當前state
account_name user,// 用戶
asset input,// 輸入資產
asset min_output,// 最小輸出資產
asset* out = nullptr) {
複製代碼
因此咱們來解讀第一行convert代碼的意思爲:
一個名爲「dan」的用戶,現有資產狀態爲上面已打印的state,輸入資產爲100個USD,最小輸出資產爲0個BTC(注意輸入資產和最小輸出資產必須是不一樣的,不然沒法轉化)。
複製代碼
下面看輸出print_\state結果:
-----------------------------
supply: 1e+11
base: 1e+08 USD
quote: 9.99999e+07 BTC
dan 96.0783 BTC
dan 0 EXC
dan -100 USD
複製代碼
結果解讀:
從新解讀這一行convert代碼的意思爲:
state數字資產(咱們最先設置的),dan根據state資產的格式拿出來本身帳戶中的100個USD(dan自己沒有USD,因此是欠款狀態)做爲抵押想exchange BTC,,而BTC是quote(base和quote也能夠理解爲用戶)的符號,因此quote的數量少了相應的100個BTC。最後,要將這100個BTC打入dan的帳戶裏面,而爲何編程了96.0783個而不是100個呢?
複製代碼
上面咱們將問題拋了出來,下面咱們對代碼進行debug,來分析這100個BTC在發放給用戶的時候是如何轉變的?咱們打個斷點,開始運行程序,走到convert函數中,因爲咱們的USD等於base的符號,因此執行到了convert_to_exchange函數。
asset connector::convert_to_exchange(exchange_state &ex, const asset &input) {
real_type R(ex.supply);// 1e+11
real_type S(balance.amount + input.amount); //100000100,等於state資產得新發行100個USD
real_type F(weight);//0.489999999999999991118,USD所佔比重,state初始化時已經設置好
real_type T(input.amount);//100
real_type ONE(1.0);//1
auto E = R * (ONE - std::pow(ONE + T / S, F));// 根據這個算法獲得對應的state資產的增髮量的值。pow是cmath庫的一個函數,有兩個參數,返回結果爲第一個參數爲底,第二個參數爲冪值的結果。
// (1e+11)*(1-(1+100/100000100)^+0.489999999999999991118),這得藉助計算器了,算出結果爲:-48999.9385,約等於程序執行結果-48999.938505084501827。
token_type issued = -E; //48999.9385,增發100個USD,實際上要增發state這麼多。
ex.supply += issued;// 更新總髮行量,加入以上計算的值。
balance.amount += input.amount;//state的USD connector(可理解爲基於某穩值數字資產下的token)的餘額能夠增長100個USD了。
return asset{issued, exchange_symbol};// 最後是以EXC資產增發48999.9385個的形式返回。
}
複製代碼
EXC是state的「原值」符號,USD和BTC是基於EXC抵押資產發行的數字token。
複製代碼
繼續調試,回到convert函數中。咱們得到了要對應增發EXC的數量,那麼要具體執行影響到state數字資產,是經過:
result.output[balance_key{user, final_output.symbol}] += final_output.amount;// 將增發EXC的數量添加至state的output集合中。
output存放形式:
結果就是EXC總帳戶經過dan增發了48999.9385,而後接下來繼續,
result.output[balance_key{user, input.symbol}] -= input.amount;
複製代碼
這是給dan帳戶進行減持,一樣的,咱們列出output的存放形式:
結果就是dan我的帳戶欠了100個USD,dan在調用convert的時候,要求最小輸出資產是BTC類型的,而如今針對輸入資產類型USD以及EXC相應的操做已經作完。下面要作的是EXC和BTC的convert。
if (min_output.symbol != final_output.symbol) {// 當計算的最終輸出資產的符號與傳入的最小輸出資產不一致時,要調用自己convert來轉換。
return convert(result, user, final_output, min_output, out);
}
複製代碼
攜帶新的參數EXC和BTC再次進入convert函數時,state數字資產已經發生了變化,它的總髮行量變爲100000048999.93851,base的USD的餘額變爲100000100,quote的BTC的餘額不變,仍舊爲1億。咱們新帶過來的參數是:
因爲咱們這一次處理的輸入資產類型就是state的默認符號EXC,因此會走另一個處理分支,根據最小輸出資產類型會執行convert_from_exchange函數:
initial_output = result.quote.convert_from_exchange(result, initial_output);
convert_from_exchange函數源碼:
asset connector::convert_from_exchange(exchange_state &ex, const asset &input) {
real_type R(ex.supply - input.amount);// 先找回原值:1e+11
real_type S(balance.amount);// BTC餘額不變,仍爲1億個1e+8
real_type F(weight);// 權重爲0.51
real_type E(input.amount);// EXC的輸入數量48999.93851
real_type ONE(1.0);
real_type T = S * (std::pow(ONE + E / R, ONE / F) - ONE);// 1e+8*((1+48999.93851/1e+11)^(1/0.51)-1),經過科學計算器了,算出結果爲:96.07833342,約等於程序執行結果96.0783334103356735645。
// 這是經過抵押資產EXC的增髮量來反推對應的BTC的增髮量。
auto out = T;
ex.supply -= input.amount;// 將EXC增發的部分減掉,實際上是維持了原有增髮量1e+11不變。
balance.amount -= token_type(out);// BTC的總量減小了96.07833342(這部分發給dan了),變爲99999903.921666592。
return asset{token_type(out), balance.symbol};//最終以BTC減掉(發放出去)96.07833342的形式返回。
}
複製代碼
它的函數體與上面的convert_to_exchange函數很類似,但細一看會發現裏面的某些數值運算髮生了變化。而後,咱們繼續回到二重convert函數中,BTC發給dan的部分(實際上從dan的角度上來說,能夠是BTC增發)具體執行爲:
result.output[balance_key{user, final_output.symbol}] += final_output.amount;// 將發給dan的96.07833342加到dan的帳戶裏。
結果就是dan帳戶中多了96.07833342個BTC。而後對做爲輸入資產的EXC進行處理:
result.output[balance_key{user, input.symbol}] -= input.amount;
結果就是EXC總帳戶經過dan減持掉48999.9385。此時,因爲上面的convert_from_exchange函數返回的是BTC的資產,與原始最小輸出資產類型相同,因此沒必要要再次進入一個convert嵌套。直接返回state,包含以上四個加粗信息,這裏再從新列出來:
1和4互相抵消,等於state的總髮行量不變,仍舊爲原始的1e+11。因此state中會新增帳戶dan的信息,它的USD和BTC以及EXC(中間涉及到了中轉交易,EXC至關於一箇中間價值錨定,用來創建兩種token交易的通道)。最終達到了與程序輸出相等的結果:
-----------------------------
supply: 1e+11
base: 1e+08 USD
quote: 9.99999e+07 BTC
dan 96.0783 BTC
dan 0 EXC
dan -100 USD
-----------------------------
複製代碼
咱們經過一個簡單的測試完成了對exchange合約的學習,exchange合約教會咱們能夠經過EOS創建本身的生態模型,通證模型,咱們能夠錨定抵押資產,發行token,經過權重的形式發行多個token等等,很是靈活,這與本篇文章前半部分所描述的那種價值穩定的數字貨幣的設計是吻合的。在測試程序中,咱們簡單實現了exchange源碼中的convert函數,各類自定義結構體,例如connector,exchange_state等等,基本上全部測試文件中的函數與結構均可以在exchange源碼中找到。咱們在上面源碼分析的過程當中還比較混沌,但經過測試文件的梳理,再回頭去看上面的源碼分析,會有新的體會。源碼中各類結構以及函數是更加精密與強壯的,可是測試文件和exchange源碼相同的是:他們的通證模型是相同的。咱們經過測試和源碼更加充分理解了EOS的靈活的通證模型。有任何問題,歡迎來討論。
圓方圓學院聚集大批區塊鏈名師,打造精品的區塊鏈技術課程。 在各大平臺都長期有優質免費公開課,歡迎報名收看。
公開課地址:ke.qq.com/course/3451…