RAM购买机制结合多种合约详解
945坏男人
发表于 2022-11-12 16:42:51
129
0
0
// native.hpp (newaccount definition is actually in eosio.system.cpp)7 \7 @+ r- B8 S8 l% Y! u
(newaccount)(updateauth)(deleteauth)(linkauth)(unlinkauth)(canceldelay)(onerror)
// eosio.system.cpp
(setram)(setparams)(setpriv)(rmvproducer)(bidname)
// delegate_bandwidth.cpp
(buyrambytes)(buyram)(sellram)(delegatebw)(undelegatebw)(refund)+ u: n( H7 B- I1 _
// voting.cpp3 o9 i) T; p3 o E0 {( L
(regproducer)(unregprod)(voteproducer)(regproxy); B6 w) X% U" x5 k. M) v* v7 m
// producer_pay.cpp
(onblock)(claimrewards): u( n: [5 H2 P0 r, r6 w- O4 T3 f
ram,cpu和net操作相关方法的都定义在delegate_bandwidth.cpp,其中和RAM相关的是buyrambytes(通过指定字节数购买ram),buyram(通过指定货币购买ram)。
delegate_bandwidth.cpp
//根据当前市场的份额,将需要购买的字节数转化为指定的EOS进行购买
void system_contract::buyrambytes( account_name payer, account_name receiver, uint32_t bytes ) {
//在数据库中查询RAMCORE发行量,默认为1000000000000002 j3 ~: j) m4 ?! r4 t4 t# t
auto itr = _rammarket.find(S(4,RAMCORE));
auto tmp = *itr;% X! f5 S0 S/ q4 j" j1 L3 z3 @, R
auto eosout = tmp.convert( asset(bytes,S(0,RAM)), CORE_SYMBOL );
//通过转化后,调用buyram使用EOS购买5 \2 l* F( j1 {1 R9 k B
buyram( payer, receiver, eosout );2 \* `2 s) u; F* Y9 |! q
}. l$ Z8 E! S: J
解析3 G; g! P8 J. \/ f" f
RAM的交易机制采用Bancor算法,使每字节的价格保持不变,通过中间代币(RAMCORE)来保证EOS和RAM之间的交易流通性。从上源码看首先获得RAMCORE的发行量,再通过tmp.convert方法RAM->RAMCORE,RAMCORE->EOS(CORE_SYMBOL)再调用buyram进行购买。这里的CORE_SYMBOL不一定是指EOS,查看core_symbol.hpp,发现源码内定义为SYS,也就是说在没有修改的前提下,需要提前发行SYS代币,才能进行RAM购买。
core_symbol.hpp
#define CORE_SYMBOL S(4,SYS)3 p2 ]' \! a9 O2 F# E% V# ]
delegate_bandwidth.cpp
void system_contract::buyram(account_name payer, account_name receiver, asset quant)
{% x: ?0 q; D0 ? l
//验证权限
require_auth(payer);+ c; g# ^9 t) S+ d4 p
//不能为0
eosio_assert(quant.amount > 0, "must purchase a positive amount");
auto fee = quant;$ s( T$ q; C+ ]
//手续费为0.5%,如果amoun为1则手续费为1,如果小于1,则手续费在amoun 0)
{
INLINE_ACTION_SENDER(eosio::token, transfer)% e4 P' p) s# E6 c
(N(eosio.token), {payer, N(active)},. o9 L0 B4 H1 h( P
{payer, N(eosio.ramfee), fee, std::string("ram fee")});
}
int64_t bytes_out;2 `0 T# \$ A* U0 L
//根据ram市场里的EOS和RAM实时汇率计算出能够购买的RAM总量
const auto &market = _rammarket.get(S(4, RAMCORE), "ram market does not exist");- K# T; o" }/ `; K( Z
_rammarket.modify(market, 0, [&](auto &es) {
//转化方法请参考下半部分/ X: d. `0 C( b, O
bytes_out = es.convert(quant_after_fee, S(0, RAM)).amount;6 |0 k, g: p2 A# B, s* F
});
//剩余总量大于0判断1 ]& ?; c- C; `; U$ `3 z7 V
eosio_assert(bytes_out > 0, "must reserve a positive amount");
//更新全局变量,总共可以使用的内存大小
_gstate.total_ram_bytes_reserved += uint64_t(bytes_out);
//更新全局变量,购买RAM冻结总金额
_gstate.total_ram_stake += quant_after_fee.amount;
user_resources_table userres(_self, receiver);5 L2 i4 W' p; \) O
auto res_itr = userres.find(receiver);
if (res_itr == userres.end())
{
//在userres表中添加ram相关记录1 ^, }0 ]5 k! z$ I$ Q. y
res_itr = userres.emplace(receiver, [&](auto &res) {
res.owner = receiver;
res.ram_bytes = bytes_out;
}); U4 {) d# R. D9 N/ {- G9 w% ?
}0 X3 J8 x& l+ t+ n3 i P- c3 [0 j
else
{
//在userres表中修改ram相关记录3 m7 L$ `! O9 e! j: p/ ?: ?
userres.modify(res_itr, receiver, [&](auto &res) {; M1 f; W! N8 t# o0 m# I0 o9 b
res.ram_bytes += bytes_out;
});0 \2 X$ I% W6 P8 d) E
}# S, } j4 X3 g5 o! m! k
//更新账号的RAM拥有量
set_resource_limits(res_itr->owner, res_itr->ram_bytes, res_itr->net_weight.amount, res_itr->cpu_weight.amount);5 o" M, p/ a. Q: L
}0 h6 g; W6 ~# A/ Z& o. {$ x* p
相关注释已经在代码中,这里还会用到一个比较重要的内容,那就是代币转化为RAM的公式,此方法请参考下面, 这方面还未深入研究会在接下来补充。
exchange_state.cpp
asset exchange_state::convert_to_exchange( connector& c, asset in ) {
real_type R(supply.amount); //RAM已经售出的总量
real_type C(c.balance.amount+in.amount); //RAM总购买金额+本次购买的量; G3 e5 J/ A/ {. ?7 T0 t" g2 R
real_type F(c.weight/1000.0);
real_type T(in.amount);* E8 ~8 _1 q; y {; W( X
real_type ONE(1.0);
real_type E = -R * (ONE - std::pow( ONE + T / C, F) );//换算出EOS对应的RAM量
//print( "E: ", E, "\n");
int64_t issued = int64_t(E); Y7 R3 ?: ?0 D" [) [
supply.amount += issued;//更新RAM已经售出的总量
c.balance.amount += in.amount;//更新RAM总购买金额6 X% e1 R4 _( g! Q H
return asset( issued, supply.symbol ); n! f( _, b3 g
}: Y5 x/ K& m- q0 M/ Y
0 H" V D L# F5 s; t
asset exchange_state::convert( asset from, symbol_type to ) {
auto sell_symbol = from.symbol;
auto ex_symbol = supply.symbol;
auto base_symbol = base.balance.symbol; ( w& \' ]! E' k4 N
auto quote_symbol = quote.balance.symbol;
//根据币种转化可以购买的RAM量* V4 _# l. `6 p9 T4 T( f
if( sell_symbol != ex_symbol ) {* k, N$ e% g& V5 ^8 t
if( sell_symbol == base_symbol ) {- l) B0 p+ Z d
from = convert_to_exchange( base, from );
} else if( sell_symbol == quote_symbol ) {
from = convert_to_exchange( quote, from );" p# Z1 w6 l- E0 l
} else { . C* q$ `* F% I X. \ u
eosio_assert( false, "invalid sell" );. O7 o; `5 _% i0 a
}+ c* C7 A3 H! r7 g. w' a
} else {
if( to == base_symbol ) {
from = convert_from_exchange( base, from );
} else if( to == quote_symbol ) {- k6 a2 S' d. X c: a) I, s/ k
from = convert_from_exchange( quote, from );
} else {
eosio_assert( false, "invalid conversion" );
}& H2 _, y: U4 Z, n
}, _: ^" t1 u1 v+ s% a
if( to != from.symbol )( u) Y/ z, ]3 ~0 A
return convert( from, to );1 g# @" h: @& m! T: v
return from;
}
convert_to_exchange的转化公式如下。
# j' ?1 \7 |6 u8 W9 N( H) K
ram购买的量是一个绝对值,是根据购买EOS的金额和当前市场内ram的数量计算出来的。一般来说在ram总量不增加的情况下,一样金额的EOS,所能获得的ram会越来越少。所以如果早期你购买了ram,然后过段时间后通过sellram卖掉ram可能还能挣钱。
成为第一个吐槽的人