EOS Bancor Network剖析

baocor网络在EOS上实现的智能合约代码:https://github.com/bancorprotocol/contracts_eos

简介

bancor网络最初是用在以太坊上为了实现代币之间自动定价,自由兑换,目前bancor网络也已经运行在eos上,bancor网络实现了eos网络中的代币自动定价和自由兑换,这里的关键是自动定价,自动定价的核心是bancor算法,既然bancor网络是一个网络,组成网络的基本要素就是有节点跟节点之间的连接,节点实现代币的自由定价,节点之间的连接就是代币的转换,那么整个网络就实现了eos中代币的自动定价跟兑换

bancor 网络节点

bancor网络节点实现节点代币跟连接器代币的自动定价,下面给出一个节点组成示意图:


bancor网络节点

T:节点代币
C1,C2,C3:连接器代币

上述节点示意图中网络节点可以有很多连接器代币(实际当中一般只有1~2个),T为节点代币,T跟C之间的转换就是bancor算法

上述节点对于代币的流向一共可以分3类:
1) 用T购买C,T进入,连接器代币C出去,T===》C
2) 用C购买T,连接器代币C进入,T出去,C===》T
3) 用C1购买C2,连接器代币C1进入,连接器代币C2出去,C1===》C2

  • 特殊节点代币
    Bancor网络代币(BNT),作为网络代币的枢纽,连接Bancor网络中的所有代币,任意一个节点的连接器代币C中一般都有该代币,这样该节点的其他连接器代币跟节点代币才能在整个bancor网络中流通

示例

打开网站https://eos.bancor.network/,我们从该网站上可以看到已经加入bancor网络的所有代币,那么这些代币就可以通过bancor网络自由兑换,例如可以发现代币EOS跟DICE已经存在于网络中,那么我们用EOS来购买DICE,购买完成之后我们可以在eospark上查看该笔trx,如下:

交易详情

该trx一共有5个action(这些内联action的完成基于require_recipient)来实现EOS到DICE代币的兑换,我们用如下示意图来展示这个过程,下图的5个步骤依次对应上述5个action

代币兑换过程

BN:bancor network
C1:eos节点
C2:dice节点

因为不管是C1还是C2它们的节点连接器中都有bnt代币,所以C1中的eos能跟C2中的dice兑换,eos===》bnt的转换由C1完成,bnt===》dice的转换由C2完成,这个2个步骤是关键步骤,它们由BancorConverter::convert函数完成,该函数位于BancorConverter合约中, 该函数是bancor网络中实现代币自由定价跟自由兑换最核心的函数,该函数做的其实就是上述网络节点示意图中代币流向的3个分类

void BancorConverter::convert(name from, eosio::asset quantity, std::string memo, name code) {
    eosio_assert(quantity.is_valid(), "invalid quantity");
    eosio_assert(quantity.amount != 0, "zero quantity is disallowed");
    auto from_amount = quantity.amount / pow(10, quantity.symbol.precision());
    auto memo_object = parse_memo(memo);
    eosio_assert(memo_object.path.size() > 1, "invalid memo format");
    settings settings_table(_self, _self.value);
    auto converter_settings = settings_table.get();
    eosio_assert(converter_settings.enabled, "converter is disabled");
    eosio_assert(converter_settings.network == from, "converter can only receive from network contract");

    auto contract_name = name(memo_object.path[0].c_str());
    eosio_assert(contract_name == _self, "wrong converter");
    auto from_path_currency = quantity.symbol.code().raw();
    auto to_path_currency = symbol_code(memo_object.path[1].c_str()).raw();
    eosio_assert(from_path_currency != to_path_currency, "cannot convert to self");
    auto smart_symbol_name = converter_settings.smart_currency.symbol.code().raw();
    auto from_token = get_reserve(from_path_currency, converter_settings);
    auto to_token = get_reserve(to_path_currency, converter_settings);

    auto from_currency = from_token.currency;
    auto to_currency = to_token.currency;
    
    auto from_contract = from_token.contract;
    auto to_contract = to_token.contract;

    bool incoming_smart_token = (from_currency.symbol.code().raw() == smart_symbol_name);
    bool outgoing_smart_token = (to_currency.symbol.code().raw() == smart_symbol_name);
    
    auto from_ratio = from_token.ratio;
    auto to_ratio = to_token.ratio;

    eosio_assert(from_token.p_enabled, "'from' token purchases disabled");
    eosio_assert(code == from_contract, "unknown 'from' contract");
    auto current_from_balance = ((get_balance(from_contract, _self, from_currency.symbol.code())).amount + from_currency.amount - quantity.amount) / pow(10, from_currency.symbol.precision()); 
    auto current_to_balance = ((get_balance(to_contract, _self, to_currency.symbol.code())).amount + to_currency.amount) / pow(10, to_currency.symbol.precision());
    auto current_smart_supply = ((get_supply(converter_settings.smart_contract, converter_settings.smart_currency.symbol.code())).amount + converter_settings.smart_currency.amount) / pow(10, converter_settings.smart_currency.symbol.precision());

    name final_to = name(memo_object.to_token.c_str());
    double smart_tokens = 0;
    double to_tokens = 0;
    int64_t total_fee_amount = 0;
    bool quick = false;

    // 对应网络节点示意图代币流向分类 1)
    if (incoming_smart_token) {
        // destory received token
        action(
            permission_level{ _self, "active"_n },
            converter_settings.smart_contract, "retire"_n,
            std::make_tuple(quantity, std::string("destroy on conversion"))
        ).send();

        smart_tokens = from_amount;
        current_smart_supply -= smart_tokens;
    }
  // 对应网络节点示意图代币流向分类 3)
    else if (!incoming_smart_token && !outgoing_smart_token && (from_ratio == to_ratio) && (converter_settings.fee == 0)) {
        to_tokens = quick_convert(current_from_balance, from_amount, current_to_balance);
        quick = true;
    }
     // 对应网络节点示意图代币流向分类 3)或 2)
    else {
        smart_tokens = calculate_purchase_return(current_from_balance, from_amount, current_smart_supply, from_ratio);
        current_smart_supply += smart_tokens;
        if (converter_settings.fee > 0) {
            double ffee = (1.0 * converter_settings.fee / 1000.0);
            auto fee = smart_tokens * ffee;
            int64_t fee_amount = (fee * pow(10, converter_settings.smart_currency.symbol.precision()));
            if (fee_amount > 0) {
                smart_tokens = smart_tokens - fee;
                total_fee_amount += fee_amount;
            }
        }
    }

    auto issue = false;
  // 对应网络节点示意图代币流向分类 2)
    if (outgoing_smart_token) {
        eosio_assert(memo_object.path.size() == 2, "smart token must be final currency");
        to_tokens = smart_tokens;
        issue = true;
    }
    // 对应网络节点示意图代币流向分类 3)
    else if (!quick) {
        if (converter_settings.fee) {
            double ffee = (1.0 * converter_settings.fee / 1000.0);
            auto fee = smart_tokens * ffee;
            int64_t fee_amount = (fee * pow(10, converter_settings.smart_currency.symbol.precision()));
            if (fee_amount > 0) {
                smart_tokens = smart_tokens - fee;
                total_fee_amount += fee_amount;
            }
        }

        to_tokens = calculate_sale_return(current_to_balance, smart_tokens, current_smart_supply, to_ratio);
    }

    int64_t to_amount = (to_tokens * pow(10, to_currency.symbol.precision()));
    EMIT_CONVERSION_EVENT(memo, from_token.contract, from_currency.symbol.code(), to_token.contract, to_currency.symbol.code(), from_amount, to_amount, total_fee_amount);

    if (incoming_smart_token || !outgoing_smart_token)
        EMIT_PRICE_DATA_EVENT(current_smart_supply, to_token.contract, to_currency.symbol.code(), current_to_balance - to_amount, to_ratio);
    if (outgoing_smart_token || !incoming_smart_token)
        EMIT_PRICE_DATA_EVENT(current_smart_supply, from_token.contract, from_currency.symbol.code(), current_from_balance, from_ratio);

    auto next_hop_memo = next_hop(memo_object);
    auto new_memo = build_memo(next_hop_memo);
    auto new_asset = asset(to_amount, to_currency.symbol);
    name inner_to = converter_settings.network;
    if (next_hop_memo.path.size() == 0) {
        inner_to = final_to;
        verify_min_return(new_asset, memo_object.min_return);
        if (converter_settings.require_balance)
            verify_entry(inner_to, to_contract, new_asset);
        new_memo = std::string("convert");
    }

    if (issue)
         // 对应网络节点示意图代币流向分类 2)
        action(
            permission_level{ _self, "active"_n },
            to_contract, "issue"_n,
            std::make_tuple(inner_to, new_asset, new_memo) 
        ).send();
     // 对应网络节点示意图代币流向分类 1)或 3)
    else
        action(
            permission_level{ _self, "active"_n },
            to_contract, "transfer"_n,
            std::make_tuple(_self, inner_to, new_asset, new_memo)
        ).send();
}

上述函数中的quick_convert原理参考 EOS中的ram购买算法(python版)中的quick_conver

  • 网络节点
    上述bancor网络节点示意图中对节点代币的配置通过BancorConverter合约中的init action完成,网络节点的连接器代币配置通过BancorConverter合约中的setreserve action完成

参考:http://www.qukuaiwang.com.cn/news/12895.html

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 157,298评论 4 360
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 66,701评论 1 290
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 107,078评论 0 237
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,687评论 0 202
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,018评论 3 286
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,410评论 1 211
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,729评论 2 310
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,412评论 0 194
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,124评论 1 239
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,379评论 2 242
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,903评论 1 257
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,268评论 2 251
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,894评论 3 233
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,014评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,770评论 0 192
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,435评论 2 269
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,312评论 2 260