首页 > EOS柚子 > 正文

干货分享丨EOS标准货币体系与源码分析(二)

EosStore  2018-05-25  EOS/EOS柚子栏目  

 

EosStore的自白

我们是由一群Eos坚定信仰者、区块链技术发烧友组成,立志与EOS持有者一起共建一个自由、开放、平等、互信的高效去中心化社区。同时作为超级节点的竞选者之一,期望可以成为其守护者以及EOS生态繁荣的建设者,并致力构造一个开放、多元、平衡的应用生态。感谢大家的支持,请与我们一起见证未来…

 

 

本篇文章是延续 “干货分享丨EOS标准货币体系与源码分析(一)” 继续讲解的。

 

正文继续:

exchange.abi

abi文件是通过eosiocpp工具通过exchange.cpp生成的,具体可参照《EOS智能合约演练》。

exchange_accounts

从这里开始我们来详细分析exchange合约的源码内容,exchange.cpp需要引用exchange_accounts, exchange_state以及market_state这三个库。其中market_state又依赖两外两个库,因此我们先从比较独立的exchange_accounts入手。

exchange_accounts.hpp

 
  1. #pragma once

  2. #include <eosiolib/asset.hpp>

  3. #include <eosiolib/multi_index.hpp>

  4.  

  5. namespace eosio {

  6.  

  7.   using boost::container::flat_map;// 相当于java中的import,下面可以直接使用flat_map方法。

  8.  

  9.   /**

  10.    *  每个用户都有他们自己的账户,并且这个账户是带有exchange合约的。这可以让他们保持跟踪一个用户是如何抵押各种扩展资产类型的。假定存储一个独立的flat_map,包含一个特定用户的所有余额,这个用户比起打破使用扩展标识来排序的多重索引表,将更加实际的

  11.    */

  12.   struct exaccount {

  13.      account_name                         owner;// uint64_t类型,64位无符号整型

  14.      flat_map<extended_symbol, int64_t>   balances;// extended_symbol是asset.hpp中定义的

  15.  

  16.      uint64_t primary_key() const { return owner; }// 结构体包含一个primary_key方法是不可变的,const,实现也有了,直接是返回owner。

  17.      EOSLIB_SERIALIZE( exaccount, (owner)(balances) )// EOSLIB_SERIALIZE这是一种自定义的模板,是一种反射机制,可以给结构体赋值,第一个参数为结构体名字,后面的参数用括号分别括起来,传入当前两个成员变量。

  18.   };

  19.  

  20.   typedef eosio::multi_index<N(exaccounts), exaccount> exaccounts;// multi_index是一个类,这行定义了一个变量exaccounts,它的类型是一种多重索引。

  21.  

  22.  

  23.   /**

  24.    *  提供一个抽象接口,为用户的余额排序。这个类缓存了数据表,以提供高效地多重访问。

  25.    */

  26.   struct exchange_accounts {

  27.      exchange_accounts( account_name code ):_this_contract(code){}// 给私有成员赋值

  28.  

  29.      void adjust_balance( account_name owner, extended_asset delta, const string& reason = string() );//调整余额,传入owner、扩展资产,reason。exchange\_accounts.cpp会实现该函数。

  30.  

  31.      private:

  32.         account_name _this_contract;// 私有成员 \_this\_contract

  33.         /**

  34.          *  保留一个缓存,用来存储我们访问的所有用户表

  35.          */

  36.         flat_map<account_name, exaccounts> exaccounts_cache;// flat_map类型的缓存exaccounts_cache,存储的是账户名和以上结构体exaccounts。

  37.   };

  38. } /// namespace eosio

multi_index这里再简单介绍一下。它的模板定义是

 
  1. template<uint64_t TableName, typename T, typename... Indices>

泛型中第一个参数是表名,第二个是多重索引。

N函数的源码:

 
  1. /**

  2.    * @brief 用来生成一个编译时间,它是64位无符号整型。传入的参数X是一个base32编码的字符串的解释。

  3.    * @ingroup types

  4.    */

  5.   #define N(X) ::eosio::string_to_name(#X)

下面来看一下exchange_accounts.cpp源码:

 
  1. #include <exchange/exchange_accounts.hpp>

  2.  

  3. namespace eosio {

  4.  

  5.   void exchange_accounts::adjust_balance( account_name owner, extended_asset delta, const string& reason ) {

  6.      (void)reason;// reason当做一个备注,不可修改的。

  7.  

  8.      auto table = exaccounts_cache.find( owner );//通过account\_name查找到对应的exaccount结构体对象数据。

  9.      if( table == exaccounts_cache.end() ) {// 如果这个数据是最后一个,则将当前数据重新包装放入exaccounts_cache,同时将exaccounts_cache第一位的数据重新赋值给table

  10.         table = exaccounts_cache.emplace( owner, exaccounts(_this_contract, owner )  ).first;

  11.      }

  12.      auto useraccounts = table->second.find( owner );//table现在有值了,在table下一个位置查找owner

  13.      if( useraccounts == table->second.end() ) {// 如果这个用户是table下一个位置的结尾数据,则将owner重新组装数据放入table

  14.         table->second.emplace( owner, [&]( auto& exa ){

  15.           exa.owner = owner;

  16.           exa.balances[delta.get_extended_symbol()] = delta.amount;

  17.           eosio_assert( delta.amount >= 0, "overdrawn balance 1" );//断言,当extended_assert资产的数目小于0时,打印日志:透支余额1

  18.         });

  19.      } else {// 如果该用户不是table下一个位置的结尾数据,则修改以该用户为key的数据,

  20.         table->second.modify( useraccounts, 0, [&]( auto& exa ) {

  21.           const auto& b = exa.balances[delta.get_extended_symbol()] = delta.amount;// 扩展标识的余额加上extended_assert资产的数目为b

  22.           eosio_assert( b >= 0, "overdrawn balance 2" );// 断言,当b小于0时,打印日志:透支余额2

  23.         });

  24.      }

  25.   }

  26.  

  27. } /// namespace eosio

它实现了adjust_balance函数。这个函数主要实现了对账户数据的管理,余额的判断与处理。

exchange_state

exchange_state库的源码我就不张贴了,这里进行一个总结:

  • exchange_state.hpp,头文件中主要声明了一些变量结构体,

    • 包括边缘状态margin_state,返回的是一个extended_asset

    • interest_shares,所有的给那些借出人分配的共享空间,当某人未借款,他们可以获得total_lendable * user_interest_shares / interest_shares。当付过利息以后,会显示在变量total_lendable。

    • exchange_state结构体是使用bancor数学创建一个在两种资产类型中的50/50的中继。这个bancor的状态,exchange是完全包含在这个结构体中。这个API没有额外的影响和使用。

  • exchange_state.cpp,源文件中主要实现了头文件中这几个结构体中的一些函数,包括

    • convert_to_exchange,通过传入一种extended_asset资产,将它转换成exchange token,相当于token在原有发行量的基础上,按照新的extended_asset资产抵押发行了新的token。

    • convert_from_exchange,通过传入一定量的exchange token(注意exchange token也是extended_asset资产类型),将其转化为其他extended_asset资产,相当于回购了部分token,降低了token保有量。

    • convert,传入一个extended_asset资产参数,以及一个extended_symbol参数,通过判断symbol的种类,调用以上convert_to_exchange或convert_from_exchange函数进行转换处理,最终将传入的extended_asset资产转换为携带extended_symbol。

    • requires_margin_call,传入一个connector,connector在以上转换函数中都作为参数并且在转换过程中发生了作用,这里是对connector参数进行判断,是否需要调用边缘处理(即与值peer_margin.total_lent.amount作比较)

下面是connector的源码部分:

 
  1. struct connector {

  2. extended_asset balance;// 余额

  3. uint32_t       weight = 500;// 权重

  4.  

  5. margin_state   peer_margin; /// peer_connector 抵押借贷余额,margin_state类型

  6.  

  7. EOSLIB_SERIALIZE( connector, (balance)(weight)(peer_margin) )还是那个初始化工具。

  8. };

exchange_state库中最重要的函数就是上面这几个转换函数,掌握这些函数都能干哪些事,未来我们可以直接测试调用或者在其他源码中出现继续分析。

market_state

这是基于以上exchange_accounts以及exchange_state两个库的库,它的内容也很多,不适宜全部粘贴出来。

  • market_state.hpp,该头文件中包含了结构体

    • margin_position,我们针对每一个market/borrowed_symbol/collateral_symbol类型的数据计算了一个唯一的作用域,然后例举了一个边缘位置表,通过这个表,每个用户可以明确地拥有一个位置,因此owner可以作为主键。

    • loan_position,借贷位置。

    • market_state(C 语法补充:结构体中也可以有private成员,这跟类很相似了其实)。与边缘位置或者限制单数一起维护了一个状态

  • market_state.cpp,源文件中实现了很多函数。这些函数实现了市场借贷关系,余额数量等操作处理,具体我们在exchange主库中通过具体业务进行介绍。

exchange

这是整个exchange合约的主库(通常我会将一个名字的头文件加源文件合并称为一个库,这也是C 的命名习惯)。

exchange.hpp

头文件,主要声明了一个类exchange,这里面包含了三个私有成员,以及七个公有函数,还有三个公有结构体,下面贴一下源码吧:

 
  1. #include <eosiolib/types.hpp>

  2. #include <eosiolib/currency.hpp>

  3. #include <boost/container/flat_map.hpp>

  4. #include <cmath>

  5. #include <exchange/market_state.hpp>

  6.  

  7. namespace eosio {

  8.  

  9.   /**

  10.    *  这个合约可以让用户在任意一对标准货币类型之间创建一个exchange,这个exchange是基于一个在购买方和发行方双边的价值等额的条件下而创建的。为了预防舍入误差,初始化金额应该包含大量的base以及quote货币的数量,并且exchange 共享应该在最大初始化金额的100倍的数量。用户在他们通过exchange交易前,必须先存入资金到exchange。每次一个exchange创建一个新的货币时,相应的交易市场制造商也会被创建。货币供应以及货币符号必须是唯一的并且它使用currency合约的表来管理。

  11.    */

  12.   class exchange {

  13.      private:

  14.         account_name      _this_contract;// 私有,账户名

  15.         currency          _excurrencies;// 货币

  16.         exchange_accounts _accounts;// exchange的账户

  17.  

  18.      public:

  19.         exchange( account_name self )

  20.         :_this_contract(self),

  21.          _excurrencies(self),

  22.          _accounts(self)

  23.         {}

  24.         // 创建

  25.         void createx( account_name    creator,

  26.                       asset           initial_supply,

  27.                       uint32_t        fee,

  28.                       extended_asset  base_deposit,

  29.                       extended_asset  quote_deposit

  30.                     );

  31.         // 订金

  32.         void deposit( account_name from, extended_asset quantity );

  33.         // 提现

  34.         void withdraw( account_name  from, extended_asset quantity );

  35.         // 借出

  36.         void lend( account_name lender, symbol_type market, extended_asset quantity );

  37.  

  38.         // 不借?

  39.         void unlend(

  40.            account_name     lender,

  41.            symbol_type      market,

  42.            double           interest_shares,

  43.            extended_symbol  interest_symbol

  44.         );

  45.  

  46.         // 边缘覆盖结构体

  47.         struct covermargin {

  48.            account_name     borrower;

  49.            symbol_type      market;

  50.            extended_asset   cover_amount;

  51.         };

  52.  

  53.         // 上侧边缘

  54.         struct upmargin {

  55.            account_name     borrower;

  56.            symbol_type      market;

  57.            extended_asset   delta_borrow;

  58.            extended_asset   delta_collateral;

  59.         };

  60.         // 交易结构体

  61.         struct trade {

  62.            account_name    seller;

  63.            symbol_type     market;

  64.            extended_asset  sell;

  65.            extended_asset  min_receive;

  66.            uint32_t        expire = 0;

  67.            uint8_t         fill_or_kill = true;

  68.         };

  69.  

  70.         // 函数名根据参数列表方法重载,在xxx上执行exchange

  71.         void on( const trade& t    );

  72.         void on( const upmargin& b );

  73.         void on( const covermargin& b );

  74.         void on( const currency::transfer& t, account_name code );

  75.  

  76.         // 应用

  77.         void apply( account_name contract, account_name act );

  78.   };

  79. } // namespace eosio

exchange.cpp

该源文件中实现了以上头文件中定义的所有公有方法。

测试

先定义两个标准货币base和quote,他们都是exchange_state类型:

 
  1. exchange_state state;

  2. state.supply = 100000000000ll;// 发行量

  3. //state.base.weight  = state.total_weight / 2.;

  4. state.base.balance.amount = 100000000;

  5. state.base.balance.symbol = "USD";

  6. state.base.weight = .49;

  7. //state.quote.weight = state.total_weight / 2.;

  8. state.quote.balance.amount = state.base.balance.amount;

  9. state.quote.balance.symbol = "BTC";

  10. state.quote.weight = .51;

  11.  

  12. print_state( state );

插曲:ubuntu编译boost库

首先在boost官网下载最新库文件,目前我下载的版本是boost167_0.tar.bz2。

  • 下载好压缩包,解压缩tar --bzip2 -xf boost167_0.tar.bz2

  • 解压后的文件夹转移到自己的习惯位置管理好,然后进入该目录

  • 先执行./booststrap.sh进行boost库编译。

  • 再执行sudo ./b2 install进行命令安装。

然后,我们再打开CLion,CMake自动编译项目eos,会发现console中已经显式编译成功的字样。

接下来继续我们的测试。直接run 主函数,首先打印出来的是"USD"和"BTC"的发行信息,

 
  1. -----------------------------

  2. supply: 1e 11

  3. base: 1e 08 USD

  4. quote: 1e 08 BTC

  5.  

  6. -----------------------------

可以看到,这与代码中定义的总发行量以及包含的两种符号类型的token的各自发行量,都是准确的。

自定义数字资产类型

exchange_state是在测试类中我们自定义的数字资产类型,下面是它的结构:

 
  1. struct exchange_state {

  2.   token_type  supply;// 发行量

  3.   symbol_type symbol = exchange_symbol;// exchange符号

  4.  

  5.   // 两个连接器base和quote

  6.   connector  base;

  7.   connector  quote;

  8.   // 交易

  9.   void transfer( account_name user, asset q ) {

  10.      output[balance_key{user,q.symbol}] = q.amount;

  11.   }

  12.   map<balance_key, token_type> output;

  13.   vector<margin>               margins;

  14. };

exchange_state数字资产中,包含一个总发行量,两个成员资产base和quote,他们是connector类型,这个类型也是自定义的(与上面介绍的源码稍有不同,稍后在测试完成以后会总结他们的区别),交易函数以及一个自定义集合output和margins,下面来看connector的定义:

 
  1. struct connector {

  2.   asset      balance; // asset资产类型

  3.   real_type  weight = 0.5;

  4.   token_type total_lent; /// 发行商从用户的贷款

  5.   token_type total_borrowed; /// 发行商借给用户

  6.   token_type total_available_to_lend; /// 可借出的有效数量

  7.   token_type interest_pool; /// 利息池,是所获得的总利息,但不一定每个用户都可以申请使用

  8.  

  9.   // 以下三个方法都在本文件下被实现了。

  10.   void  borrow( exchange_state& ex, const asset& amount_to_borrow );

  11.   asset convert_to_exchange( exchange_state& ex, const asset& input );

  12.   asset convert_from_exchange( exchange_state& ex, const asset& input );

  13. };

这个connector有一个余额,一个权重(可理解为占有exchange_state数字资产的比例),它的一些银行资产功能属性,贷款拆借利息等,以及connector本身作为资产可以与其他exchange_state数字资产进行转换,拆借等功能。余额成员是asset资产类型,这个类型也是一个自定义结构体:

 
  1. struct asset {

  2.   token_type amount;

  3.   symbol_type symbol;

  4. };

它具备一个总数量和符号两个成员。所以以上我们给exchange_state数字资产定义了两个connector,“BTC”和“USD”以及它们各自的发行量,正是采用这个asset的结构进行赋值的。

打印出state内容以后,显示的是两种token"USD"和"BTC"的发行信息,接下来,我们利用exchange中的一些函数功能进行两种token之间的转换及交易。

 
  1. auto new_state = convert(state, "dan", asset{100, "USD"}, asset{0, "BTC"});

  2. print_state(new_state);

看一下这里面的convert函数的声明:

 
  1. /**

  2. *  通过给出的一个当前state,计算出一个新的state返回。

  3. */

  4. exchange_state convert( const exchange_state& current,// 当前state

  5.                        account_name user,// 用户

  6.                        asset        input,// 输入资产

  7.                        asset        min_output,// 最小输出资产

  8.                        asset*       out = nullptr) {

所以我们来解读第一行convert代码的意思为:

一个名为“dan”的用户,现有资产状态为上面已打印的state,输入资产为100个USD,最小输出资产为0个BTC(注意输入资产和最小输出资产必须是不同的,否则无法转化)。

下面看输出print_\state结果:

 
  1. -----------------------------

  2. supply: 1e 11

  3. base: 1e 08 USD

  4. quote: 9.99999e 07 BTC

  5. dan  96.0783 BTC

  6. dan  0 EXC

  7. dan  -100 USD

结果解读:

  • supply和base的数量都没变

  • quote的数量少了100个BTC(0.00001e 07)

  • dan的BTC多出来96.0783个。

  • dan的EXC为0(本次交易中没有涉及到,EXC是默认token符号)

  • dan的USD少了100个。

重新解读这一行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函数。

 
  1. asset connector::convert_to_exchange(exchange_state &ex, const asset &input) {

  2.  

  3.    real_type R(ex.supply);// 1e 11

  4.    real_type S(balance.amount input.amount); //100000100,等于state资产得新发行100个USD

  5.    real_type F(weight);//0.489999999999999991118,USD所占比重,state初始化时已经设置好

  6.    real_type T(input.amount);//100

  7.    real_type ONE(1.0);//1

  8.  

  9.    auto E = R * (ONE - std::pow(ONE T / S, F));// 根据这个算法得到对应的state资产的增发量的值。pow是cmath库的一个函数,有两个参数,返回结果为第一个参数为底,第二个参数为幂值的结果。

  10.    // (1e 11)*(1-(1 100/100000100)^ 0.489999999999999991118),这得借助计算器了,算出结果为:-48999.9385,约等于程序执行结果-48999.938505084501827。

  11.  

  12.    token_type issued = -E; //48999.9385,增发100个USD,实际上要增发state这么多。

  13.  

  14.    ex.supply = issued;// 更新总发行量,加入以上计算的值。

  15.    balance.amount = input.amount;//state的USD connector(可理解为基于某稳值数字资产下的token)的余额可以增加100个USD了。

  16.  

  17.    return asset{issued, exchange_symbol};// 最后是以EXC资产增发48999.9385个的形式返回。

  18. }

EXC是state的“原值”符号,USD和BTC是基于EXC抵押资产发行的数字token。

继续调试,回到convert函数中。我们获得了要对应增发EXC的数量,那么要具体执行影响到state数字资产,是通过:

 
  1. result.output[balance_key{user, final_output.symbol}] = final_output.amount;// 将增发EXC的数量添加至state的output集合中。

output存放形式:

  • 集合中一个元素位置,下标为0开始存储。

  • 每个元素是一个pair类型。不懂C 中pair类型的可以参考《C 语法》。可以理解为一个元组,包含一对值first和second。

  • first是一个自定义结构体balance_key,包含一个账户名称成员和一个符号成员。这里对应的是"dan","EXC"。

  • second是一个增发量48999.9385。

结果就是EXC总账户通过dan增发了48999.9385,然后接下来继续,

 
  1. result.output[balance_key{user, input.symbol}] -= input.amount;

这是给dan账户进行减持,同样的,我们列出output的存放形式:

  • 下标1

  • pair类型,first,second

  • first是"dan","USD"

  • second是一个销毁量100个。

结果就是dan个人账户欠了100个USD,dan在调用convert的时候,要求最小输出资产是BTC类型的,而现在针对输入资产类型USD以及EXC相应的操作已经做完。下面要做的是EXC和BTC的convert。

 
  1. if (min_output.symbol != final_output.symbol) {// 当计算的最终输出资产的符号与传入的最小输出资产不一致时,要调用本身convert来转换。

  2.    return convert(result, user, final_output, min_output, out);

  3. }

携带新的参数EXC和BTC再次进入convert函数时,state数字资产已经发生了变化,它的总发行量变为100000048999.93851,base的USD的余额变为100000100,quote的BTC的余额不变,仍旧为1亿。我们新带过来的参数是:

  • 48999.938505084501个EXC作为输入资产

  • 最小输出资产仍旧为第一次调用convert的0个BTC

由于我们这一次处理的输入资产类型就是state的默认符号EXC,所以会走另外一个处理分支,根据最小输出资产类型会执行convert_from_exchange函数:

 
  1. initial_output = result.quote.convert_from_exchange(result, initial_output);

convert_from_exchange函数源码:

 
  1. asset connector::convert_from_exchange(exchange_state &ex, const asset &input) {

  2.  

  3.    real_type R(ex.supply - input.amount);// 先找回原值:1e 11

  4.    real_type S(balance.amount);// BTC余额不变,仍为1亿个1e 8

  5.    real_type F(weight);// 权重为0.51

  6.    real_type E(input.amount);// EXC的输入数量48999.93851

  7.    real_type ONE(1.0);

  8.  

  9.    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。

  10.    // 这是通过抵押资产EXC的增发量来反推对应的BTC的增发量。

  11.  

  12.    auto out = T;

  13.  

  14.    ex.supply -= input.amount;// 将EXC增发的部分减掉,其实是维持了原有增发量1e 11不变。

  15.    balance.amount -= token_type(out);// BTC的总量减少了96.07833342(这部分发给dan了),变为99999903.921666592。

  16.    return asset{token_type(out), balance.symbol};//最终以BTC减掉(发放出去)96.07833342的形式返回。

  17. }

它的函数体与上面的convert_to_exchange函数很相似,但细一看会发现里面的某些数值运算发生了变化。然后,我们继续回到二重convert函数中,BTC发给dan的部分(实际上从dan的角度上来讲,可以是BTC增发)具体执行为:

 
  1. result.output[balance_key{user, final_output.symbol}] = final_output.amount;// 将发给dan的96.07833342加到dan的账户里。

结果就是dan账户中多了96.07833342个BTC。然后对作为输入资产的EXC进行处理:

 
  1. result.output[balance_key{user, input.symbol}] -= input.amount;

结果就是EXC总账户通过dan减持掉48999.9385。此时,由于上面的convert_from_exchange函数返回的是BTC的资产,与原始最小输出资产类型相同,所以不必要再次进入一个convert嵌套。直接返回state,包含以上四个加粗信息,这里再重新列出来:

  1. EXC总账户通过dan增发了48999.9385

  2. dan个人账户欠了100个USD

  3. dan账户中多了96.07833342个BTC

  4. EXC总账户通过dan减持掉48999.9385

1和4互相抵消,等于state的总发行量不变,仍旧为原始的1e 11。所以state中会新增账户dan的信息,它的USD和BTC以及EXC(中间涉及到了中转交易,EXC相当于一个中间价值锚定,用来建立两种token交易的通道)。最终达到了与程序输出相等的结果:

 
  1. -----------------------------

  2. supply: 1e 11

  3. base: 1e 08 USD

  4. quote: 9.99999e 07 BTC

  5. dan  96.0783 BTC

  6. dan  0 EXC

  7. dan  -100 USD

  8.  

  9. -----------------------------

总结

我们通过一个简单的测试完成了对exchange合约的学习,exchange合约教会我们可以通过EOS建立自己的生态模型,通证模型,我们可以锚定抵押资产,发行token,通过权重的形式发行多个token等等,非常灵活,这与本篇文章前半部分所描述的那种价值稳定的数字货币的设计是吻合的。在测试程序中,我们简单实现了exchange源码中的convert函数,各种自定义结构体,例如connector,exchange_state等等,基本上所有测试文件中的函数与结构都可以在exchange源码中找到。我们在上面源码分析的过程中还比较混沌,但通过测试文件的梳理,再回头去看上面的源码分析,会有新的体会。源码中各种结构以及函数是更加精密与强壮的,但是测试文件和exchange源码相同的是:他们的通证模型是相同的。我们通过测试和源码更加充分理解了EOS的灵活的通证模型。有任何问题,欢迎来讨论。

参考资料

  • EOS源码

 

 

-END-

 

 

 

团队介绍:

Eos.Store团队是由海内外知名技术专家引领的一批充满热情的EOS支持者组成,团队以持续维护EOS生态为核心,致力于构造一个开放多元平衡的应用生态。

 

节点域名:eos.store

 

 

 

扫描二维码添加EosStore小秘

备注“吃柚子”

即可进入超级节点社区&DApp技术交流群

和我们一起见证未来!

 

 

你可以通过以下方式

联系到我们

Email

market@eos.store

Telegram

https://t.me/StoreEos

Website

https://www.eos.store 

Twitter

https://twitter.com/StoreEos 

Github

https://github.com/eosstore  

Steemit

https://steemit.com/@eos.store

版权信息
作者:刘文彬
来源:EosStore

关于我们

联系我们

作者进驻

手机版

Copyright © 2013 比特巴 www.btb8.com
始建于2013年,提供比特币 区块链及数字货币新闻、技术教程、测评、项目周报、人物等资讯
本页面提供的是EOS新闻资讯,EOS币为区块链奇才BM领导开发的类似操作系统的区块链架构平台,旨在实现分布式应用的性能扩展。