RAM购买机制结合多种合约详解
945坏男人
发表于 2022-11-12 16:42:51
110
0
0
// native.hpp (newaccount definition is actually in eosio.system.cpp)
(newaccount)(updateauth)(deleteauth)(linkauth)(unlinkauth)(canceldelay)(onerror)
// eosio.system.cpp
(setram)(setparams)(setpriv)(rmvproducer)(bidname)
// delegate_bandwidth.cpp
(buyrambytes)(buyram)(sellram)(delegatebw)(undelegatebw)(refund)
// voting.cpp
(regproducer)(unregprod)(voteproducer)(regproxy)2 W+ s" V! T2 y% e
// producer_pay.cpp4 A- c6 E1 w6 z5 W F1 F
(onblock)(claimrewards)
ram,cpu和net操作相关方法的都定义在delegate_bandwidth.cpp,其中和RAM相关的是buyrambytes(通过指定字节数购买ram),buyram(通过指定货币购买ram)。7 m3 N" k3 C7 N2 ^( Q
delegate_bandwidth.cpp
//根据当前市场的份额,将需要购买的字节数转化为指定的EOS进行购买' F6 D7 m3 [2 N' P' H" {
void system_contract::buyrambytes( account_name payer, account_name receiver, uint32_t bytes ) {
//在数据库中查询RAMCORE发行量,默认为100000000000000$ w# x- A3 v3 c
auto itr = _rammarket.find(S(4,RAMCORE));+ z8 w% S) w0 o% B' ?3 I
auto tmp = *itr;2 D4 l1 l$ S' B
auto eosout = tmp.convert( asset(bytes,S(0,RAM)), CORE_SYMBOL );2 k! s- h7 Z+ P# x$ i/ Y- C; K% J
//通过转化后,调用buyram使用EOS购买
buyram( payer, receiver, eosout );
} |! c" N6 Q; q% T2 F/ P2 P8 K
解析
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 y2 p" H8 Z3 m4 @
delegate_bandwidth.cpp% ? }. y N. q: b4 y
void system_contract::buyram(account_name payer, account_name receiver, asset quant)
{2 A! S/ x I' V6 I( B3 g
//验证权限. Q, y$ t9 A& e0 t7 E. I6 S
require_auth(payer);+ I9 f8 Q$ k. {4 L* H# L$ O- X0 a
//不能为0
eosio_assert(quant.amount > 0, "must purchase a positive amount");8 g9 e$ H7 T! ~, F' D
auto fee = quant;
//手续费为0.5%,如果amoun为1则手续费为1,如果小于1,则手续费在amoun 0)- t9 ]3 ?* H4 k6 k6 O
{% m+ |' |0 ]2 `$ z& _/ _- d; [
INLINE_ACTION_SENDER(eosio::token, transfer)
(N(eosio.token), {payer, N(active)},
{payer, N(eosio.ramfee), fee, std::string("ram fee")});
}: S; {3 R+ D1 u2 n! y3 A! V$ g
int64_t bytes_out;5 f/ M9 n& V4 ?! b# S1 c
//根据ram市场里的EOS和RAM实时汇率计算出能够购买的RAM总量8 {8 |3 ]/ {1 H* p- R4 L
const auto &market = _rammarket.get(S(4, RAMCORE), "ram market does not exist");( f, j5 p0 y1 U$ Z& \
_rammarket.modify(market, 0, [&](auto &es) {
//转化方法请参考下半部分
bytes_out = es.convert(quant_after_fee, S(0, RAM)).amount;- C& C0 C* O/ [5 E- I+ T
});
//剩余总量大于0判断
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;8 x6 |% a0 D* {
user_resources_table userres(_self, receiver);
auto res_itr = userres.find(receiver);
if (res_itr == userres.end()), f( Y$ L' C: h4 x+ e+ d, A
{# v. v! `1 m( q
//在userres表中添加ram相关记录
res_itr = userres.emplace(receiver, [&](auto &res) {
res.owner = receiver;
res.ram_bytes = bytes_out;
});
}8 b' r2 ~! d5 I. z$ S
else, a& }1 o0 }- E C" N$ }9 C
{
//在userres表中修改ram相关记录
userres.modify(res_itr, receiver, [&](auto &res) {
res.ram_bytes += bytes_out;5 ?; t# `! @5 J6 Z
});- Z( Z# _( P) h$ ?( p( S
}
//更新账号的RAM拥有量' [9 `( v# L5 m5 v
set_resource_limits(res_itr->owner, res_itr->ram_bytes, res_itr->net_weight.amount, res_itr->cpu_weight.amount);2 P; b# { l2 W% e
}
相关注释已经在代码中,这里还会用到一个比较重要的内容,那就是代币转化为RAM的公式,此方法请参考下面, 这方面还未深入研究会在接下来补充。6 x5 d) ]( a: X4 y
exchange_state.cpp6 w+ G- S" e+ X. ~7 x
asset exchange_state::convert_to_exchange( connector& c, asset in ) {
real_type R(supply.amount); //RAM已经售出的总量) E1 e, l& Q* ]1 f' J5 A; S
real_type C(c.balance.amount+in.amount); //RAM总购买金额+本次购买的量
real_type F(c.weight/1000.0);8 p' Z n1 \8 v, P
real_type T(in.amount);
real_type ONE(1.0);
real_type E = -R * (ONE - std::pow( ONE + T / C, F) );//换算出EOS对应的RAM量5 I, `1 M7 [( N
//print( "E: ", E, "\n");
int64_t issued = int64_t(E);3 w6 W9 ]+ Q" ^( \+ f
supply.amount += issued;//更新RAM已经售出的总量% s0 `) A( S9 b" _1 N
c.balance.amount += in.amount;//更新RAM总购买金额3 I% p5 K0 E% |
return asset( issued, supply.symbol );+ c: ?/ d2 ~- m8 c
}
& [$ T _6 L! v0 _& U6 o3 t
asset exchange_state::convert( asset from, symbol_type to ) {
auto sell_symbol = from.symbol;
auto ex_symbol = supply.symbol; 1 e: m# ~( p/ d% p1 c5 U, [) E2 x
auto base_symbol = base.balance.symbol;
auto quote_symbol = quote.balance.symbol;
4 v$ y/ w( S7 U4 k: P
//根据币种转化可以购买的RAM量, y0 y3 Q6 C; D+ G. ^
if( sell_symbol != ex_symbol ) {
if( sell_symbol == base_symbol ) {
from = convert_to_exchange( base, from );+ ?- f3 F! D6 j% i
} else if( sell_symbol == quote_symbol ) {! d9 R2 Q* _1 f. w- Q) i
from = convert_to_exchange( quote, from );7 |9 d! O. I4 y0 f5 N
} else {
eosio_assert( false, "invalid sell" );" p+ D% ^" g4 M7 ~6 {. k" d
}: b; R& u- Q5 E
} else {: ^/ m0 }8 @6 E- M/ h
if( to == base_symbol ) {
from = convert_from_exchange( base, from ); 0 `+ B+ I9 H a; r* ?2 p
} else if( to == quote_symbol ) {: `# {. T' `+ N1 I0 `' r
from = convert_from_exchange( quote, from ); - F5 s4 [3 S i6 R; i
} else {; X$ A# J' p; Y* l; C/ R6 C p+ p, @
eosio_assert( false, "invalid conversion" );
}3 h* J. @6 j+ Y$ n. g
}$ i. F( F% g0 u- H8 z
if( to != from.symbol )
return convert( from, to );: p G0 W' Y2 C% a1 q
return from;
}
convert_to_exchange的转化公式如下。7 o, i7 _" t, K& c6 d' S9 d6 I, t
+ U+ {0 ~7 t% V6 C, _
ram购买的量是一个绝对值,是根据购买EOS的金额和当前市场内ram的数量计算出来的。一般来说在ram总量不增加的情况下,一样金额的EOS,所能获得的ram会越来越少。所以如果早期你购买了ram,然后过段时间后通过sellram卖掉ram可能还能挣钱。
成为第一个吐槽的人