提交 e35b0e3a 编写于 作者: D Daniel Larimer

fix pricing model on RAM

上级 eb9f34f2
...@@ -35,7 +35,7 @@ namespace eosiosystem { ...@@ -35,7 +35,7 @@ namespace eosiosystem {
account_name owner; account_name owner;
asset net_weight; asset net_weight;
asset cpu_weight; asset cpu_weight;
uint64_t storage_bytes = 0; int64_t storage_bytes = 0;
uint64_t primary_key()const { return owner; } uint64_t primary_key()const { return owner; }
...@@ -102,7 +102,7 @@ namespace eosiosystem { ...@@ -102,7 +102,7 @@ namespace eosiosystem {
user_resources_table userres( _self, newact); user_resources_table userres( _self, newact);
auto r = userres.emplace( newact, [&]( auto& res ) { userres.emplace( newact, [&]( auto& res ) {
res.owner = newact; res.owner = newact;
}); });
...@@ -117,21 +117,12 @@ namespace eosiosystem { ...@@ -117,21 +117,12 @@ namespace eosiosystem {
* This action will buy an exact amount of ram and bill the payer the current market price. * This action will buy an exact amount of ram and bill the payer the current market price.
*/ */
void system_contract::buyrambytes( account_name payer, account_name receiver, uint32_t bytes ) { void system_contract::buyrambytes( account_name payer, account_name receiver, uint32_t bytes ) {
const double system_token_supply = eosio::token(N(eosio.token)).get_supply(eosio::symbol_type(system_token_symbol).name()).amount; auto itr = _rammarket.find(S(4,RAMEOS));
const double unstaked_token_supply = system_token_supply - _gstate.total_storage_stake.amount; auto tmp = *itr;
auto eosout = tmp.convert( asset(bytes,S(0,RAM)), S(4,EOS) );
print( "eosout: ", eosout, "\n" );
const double R = unstaked_token_supply; buyram( payer, receiver, eosout );
const double C = _gstate.free_ram() + bytes;
const double F = _gstate.storage_reserve_ratio / 10000.0;
const double T = bytes;
const double ONE(1.0);
double E = -R * (ONE - std::pow( ONE + T/C, F ) );
int64_t tokens_out = int64_t(E*1.0105);
print( "desired ram: ", bytes, "\n" );
buyram( payer, receiver, asset(tokens_out) );
} }
...@@ -154,20 +145,15 @@ namespace eosiosystem { ...@@ -154,20 +145,15 @@ namespace eosiosystem {
{ payer, N(eosio), quant, std::string("buy ram") } ); { payer, N(eosio), quant, std::string("buy ram") } );
} }
const double system_token_supply = eosio::token(N(eosio.token)).get_supply(eosio::symbol_type(system_token_symbol).name()).amount; print( "free ram: ", _gstate.free_ram(), "\n");
const double unstaked_token_supply = system_token_supply - _gstate.total_storage_stake.amount;
print( "free ram: ", _gstate.free_ram(), " tokens: ", system_token_supply, " unstaked: ", unstaked_token_supply, "\n" ); int64_t bytes_out;
const double E = quant.amount; auto itr = _rammarket.find(S(4,RAMEOS));
const double R = unstaked_token_supply - E; _rammarket.modify( itr, 0, [&]( auto& es ) {
const double C = _gstate.free_ram(); //free_ram; bytes_out = es.convert( quant, S(0,RAM) ).amount;
const double F = 1./(_gstate.storage_reserve_ratio/10000.0); /// 10% reserve ratio pricing, assumes only 10% of tokens will ever want to stake for ram });
const double ONE(1.0);
double T = C * (std::pow( ONE + E/R, F ) - ONE);
T *= .99; /// 1% fee on every conversion
int64_t bytes_out = static_cast<int64_t>(T);
print( "ram bytes out: ", bytes_out, "\n" ); print( "ram bytes out: ", bytes_out, "\n" );
eosio_assert( bytes_out > 0, "must reserve a positive amount" ); eosio_assert( bytes_out > 0, "must reserve a positive amount" );
...@@ -180,11 +166,11 @@ namespace eosiosystem { ...@@ -180,11 +166,11 @@ namespace eosiosystem {
if( res_itr == userres.end() ) { if( res_itr == userres.end() ) {
res_itr = userres.emplace( receiver, [&]( auto& res ) { res_itr = userres.emplace( receiver, [&]( auto& res ) {
res.owner = receiver; res.owner = receiver;
res.storage_bytes = uint64_t(bytes_out); res.storage_bytes = bytes_out;
}); });
} else { } else {
userres.modify( res_itr, receiver, [&]( auto& res ) { userres.modify( res_itr, receiver, [&]( auto& res ) {
res.storage_bytes += uint64_t(bytes_out); res.storage_bytes += bytes_out;
}); });
} }
set_resource_limits( res_itr->owner, res_itr->storage_bytes, res_itr->net_weight.amount, res_itr->cpu_weight.amount ); set_resource_limits( res_itr->owner, res_itr->storage_bytes, res_itr->net_weight.amount, res_itr->cpu_weight.amount );
...@@ -197,35 +183,30 @@ namespace eosiosystem { ...@@ -197,35 +183,30 @@ namespace eosiosystem {
* and selling ram. * and selling ram.
*/ */
void system_contract::sellram( account_name account, uint32_t bytes ) { void system_contract::sellram( account_name account, uint32_t bytes ) {
require_auth( account );
user_resources_table userres( _self, account ); user_resources_table userres( _self, account );
auto res_itr = userres.find( account ); auto res_itr = userres.find( account );
eosio_assert( res_itr != userres.end(), "no resource row" ); eosio_assert( res_itr != userres.end(), "no resource row" );
eosio_assert( res_itr->storage_bytes >= bytes, "insufficient quota" ); eosio_assert( res_itr->storage_bytes >= bytes, "insufficient quota" );
const double system_token_supply = eosio::token(N(eosio.token)).get_supply(eosio::symbol_type(system_token_symbol).name()).amount; asset tokens_out;
const double unstaked_token_supply = system_token_supply - _gstate.total_storage_stake.amount; auto itr = _rammarket.find(S(4,RAMEOS));
_rammarket.modify( itr, 0, [&]( auto& es ) {
const double R = unstaked_token_supply; tokens_out = es.convert( asset(bytes,S(0,RAM)), S(4,EOS) );
const double C = _gstate.free_ram() + bytes; print( "out: ", tokens_out, "\n" );
const double F = _gstate.storage_reserve_ratio / 10000.0; });
const double T = bytes;
const double ONE(1.0);
double E = -R * (ONE - std::pow( ONE + T/C, F ) );
E *= .99; /// 1% fee on every conversion,
/// let the system contract profit on speculation while preventing abuse caused by rounding errors
int64_t tokens_out = int64_t(E);
eosio_assert( tokens_out > 0, "must free at least one token" );
_gstate.total_storage_bytes_reserved -= bytes; _gstate.total_storage_bytes_reserved -= bytes;
_gstate.total_storage_stake.amount -= tokens_out; _gstate.total_storage_stake.amount -= tokens_out.amount;
//// this shouldn't happen, but just in case it does we should prevent it
eosio_assert( _gstate.total_storage_stake.amount >= 0, "error, attempt to unstake more tokens than previously staked" );
userres.modify( res_itr, account, [&]( auto& res ) { userres.modify( res_itr, account, [&]( auto& res ) {
res.storage_bytes -= bytes; res.storage_bytes -= bytes;
}); });
set_resource_limits( res_itr->owner, res_itr->storage_bytes, uint64_t(res_itr->net_weight.amount), uint64_t(res_itr->cpu_weight.amount) ); set_resource_limits( res_itr->owner, res_itr->storage_bytes, res_itr->net_weight.amount, res_itr->cpu_weight.amount );
if( N(eosio) != account ) { if( N(eosio) != account ) {
INLINE_ACTION_SENDER(eosio::token, transfer)( N(eosio.token), {N(eosio),N(active)}, INLINE_ACTION_SENDER(eosio::token, transfer)( N(eosio.token), {N(eosio),N(active)},
...@@ -281,7 +262,7 @@ namespace eosiosystem { ...@@ -281,7 +262,7 @@ namespace eosiosystem {
}); });
} }
set_resource_limits( tot_itr->owner, tot_itr->storage_bytes, uint64_t(tot_itr->net_weight.amount), uint64_t(tot_itr->cpu_weight.amount) ); set_resource_limits( tot_itr->owner, tot_itr->storage_bytes, tot_itr->net_weight.amount, tot_itr->cpu_weight.amount );
if( N(eosio) != from) { if( N(eosio) != from) {
INLINE_ACTION_SENDER(eosio::token, transfer)( N(eosio.token), {from,N(active)}, INLINE_ACTION_SENDER(eosio::token, transfer)( N(eosio.token), {from,N(active)},
......
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
#include "delegate_bandwidth.cpp" #include "delegate_bandwidth.cpp"
#include "producer_pay.cpp" #include "producer_pay.cpp"
#include "voting.cpp" #include "voting.cpp"
#include "exchange_state.cpp"
namespace eosiosystem { namespace eosiosystem {
...@@ -12,10 +13,27 @@ namespace eosiosystem { ...@@ -12,10 +13,27 @@ namespace eosiosystem {
:native(s), :native(s),
_voters(_self,_self), _voters(_self,_self),
_producers(_self,_self), _producers(_self,_self),
_global(_self,_self) _global(_self,_self),
_rammarket(_self,_self)
{ {
print( "construct system\n" ); print( "construct system\n" );
_gstate = _global.exists() ? _global.get() : get_default_parameters(); _gstate = _global.exists() ? _global.get() : get_default_parameters();
auto itr = _rammarket.find(S(4,RAMEOS));
if( itr == _rammarket.end() ) {
auto system_token_supply = eosio::token(N(eosio.token)).get_supply(eosio::symbol_type(system_token_symbol).name()).amount;
itr = _rammarket.emplace( _self, [&]( auto& m ) {
m.supply.amount = 100000000000000ll;
m.supply.symbol = S(4,RAMEOS);
m.base.balance.amount = int64_t(_gstate.free_ram());
m.base.balance.symbol = S(0,RAM);
m.quote.balance.amount = system_token_supply / 1000;
m.quote.balance.symbol = S(4,EOS);
});
} else {
print( "ram market already created" );
}
} }
eosio_global_state system_contract::get_default_parameters() { eosio_global_state system_contract::get_default_parameters() {
......
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
#include <eosiolib/asset.hpp> #include <eosiolib/asset.hpp>
#include <eosiolib/privileged.hpp> #include <eosiolib/privileged.hpp>
#include <eosiolib/singleton.hpp> #include <eosiolib/singleton.hpp>
#include <eosio.system/exchange_state.hpp>
#include <string> #include <string>
...@@ -116,6 +117,7 @@ namespace eosiosystem { ...@@ -116,6 +117,7 @@ namespace eosiosystem {
global_state_singleton _global; global_state_singleton _global;
eosio_global_state _gstate; eosio_global_state _gstate;
rammarket _rammarket;
public: public:
system_contract( account_name s ); system_contract( account_name s );
......
#include <exchange/exchange_state.hpp>
namespace eosiosystem {
asset exchange_state::convert_to_exchange( connector& c, asset in ) {
real_type R(supply.amount);
real_type C(c.balance.amount+in.amount);
real_type F(c.weight/1000.0);
real_type T(in.amount);
real_type ONE(1.0);
real_type E = -R * (ONE - std::pow( ONE + T / C, F) );
//print( "E: ", E, "\n");
int64_t issued = int64_t(E);
supply.amount += issued;
c.balance.amount += in.amount;
return asset( issued, supply.symbol );
}
asset exchange_state::convert_from_exchange( connector& c, asset in ) {
eosio_assert( in.symbol== supply.symbol, "unexpected asset symbol input" );
real_type R(supply.amount - in.amount);
real_type C(c.balance.amount);
real_type F(1000.0/c.weight);
real_type E(in.amount);
real_type ONE(1.0);
real_type T = C * (std::pow( ONE + E/R, F) - ONE);
//print( "T: ", T, "\n");
int64_t out = int64_t(T);
supply.amount -= in.amount;
c.balance.amount -= out;
return asset( out, c.balance.symbol );
}
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;
auto quote_symbol = quote.balance.symbol;
//print( "From: ", from, " TO ", asset( 0,to), "\n" );
//print( "base: ", base_symbol, "\n" );
//print( "quote: ", quote_symbol, "\n" );
//print( "ex: ", supply.symbol, "\n" );
if( sell_symbol != ex_symbol ) {
if( sell_symbol == base_symbol ) {
from = convert_to_exchange( base, from );
} else if( sell_symbol == quote_symbol ) {
from = convert_to_exchange( quote, from );
} else {
eosio_assert( false, "invalid sell" );
}
} else {
if( to == base_symbol ) {
from = convert_from_exchange( base, from );
} else if( to == quote_symbol ) {
from = convert_from_exchange( quote, from );
} else {
eosio_assert( false, "invalid conversion" );
}
}
if( to != from.symbol )
return convert( from, to );
return from;
}
} /// namespace eosiosystem
#pragma once
#include <eosiolib/asset.hpp>
namespace eosiosystem {
using eosio::asset;
using eosio::symbol_type;
typedef double real_type;
/**
* Uses Bancor math to create a 50/50 relay between two asset types. The state of the
* bancor exchange is entirely contained within this struct. There are no external
* side effects associated with using this API.
*/
struct exchange_state {
asset supply;
struct connector {
asset balance;
double weight = .5;
EOSLIB_SERIALIZE( connector, (balance)(weight) )
};
connector base;
connector quote;
uint64_t primary_key()const { return supply.symbol; }
asset convert_to_exchange( connector& c, asset in );
asset convert_from_exchange( connector& c, asset in );
asset convert( asset from, symbol_type to );
EOSLIB_SERIALIZE( exchange_state, (supply)(base)(quote) )
};
typedef eosio::multi_index<N(rammarket), exchange_state> rammarket;
} /// namespace eosiosystem
...@@ -39,7 +39,7 @@ namespace eosiosystem { ...@@ -39,7 +39,7 @@ namespace eosiosystem {
* @pre authority of producer to register * @pre authority of producer to register
* *
*/ */
void system_contract::regproducer( const account_name producer, const public_key& producer_key, const std::string& url ) { //, const eosio_parameters& prefs ) { void system_contract::regproducer( const account_name producer, const eosio::public_key& producer_key, const std::string& url ) { //, const eosio_parameters& prefs ) {
eosio_assert( url.size() < 512, "url too long" ); eosio_assert( url.size() < 512, "url too long" );
//eosio::print("produce_key: ", producer_key.size(), ", sizeof(public_key): ", sizeof(public_key), "\n"); //eosio::print("produce_key: ", producer_key.size(), ", sizeof(public_key): ", sizeof(public_key), "\n");
require_auth( producer ); require_auth( producer );
...@@ -67,7 +67,7 @@ namespace eosiosystem { ...@@ -67,7 +67,7 @@ namespace eosiosystem {
const auto& prod = _producers.get( producer ); const auto& prod = _producers.get( producer );
_producers.modify( prod, 0, [&]( producer_info& info ){ _producers.modify( prod, 0, [&]( producer_info& info ){
info.producer_key = public_key(); info.producer_key = eosio::public_key();
}); });
} }
......
...@@ -37,18 +37,18 @@ public: ...@@ -37,18 +37,18 @@ public:
create_accounts( { N(eosio.token) } ); create_accounts( { N(eosio.token) } );
produce_blocks( 100 ); produce_blocks( 100 );
set_code( config::system_account_name, eosio_system_wast );
set_abi( config::system_account_name, eosio_system_abi );
set_code( N(eosio.token), eosio_token_wast ); set_code( N(eosio.token), eosio_token_wast );
set_abi( N(eosio.token), eosio_token_abi ); set_abi( N(eosio.token), eosio_token_abi );
create_currency( N(eosio.token), config::system_account_name, asset::from_string("1000000000.0000 EOS") ); create_currency( N(eosio.token), config::system_account_name, asset::from_string("10000000000.0000 EOS") );
issue(config::system_account_name, "100000000.0000 EOS"); issue(config::system_account_name, "1000000000.0000 EOS");
BOOST_REQUIRE_EQUAL( asset::from_string("1000000000.0000 EOS"), get_balance( "eosio" ) );
set_code( config::system_account_name, eosio_system_wast );
set_abi( config::system_account_name, eosio_system_abi );
produce_blocks(); produce_blocks();
BOOST_REQUIRE_EQUAL( asset::from_string("1000000000.0000 EOS"), get_balance( "eosio" ) );
create_account_with_resources( N(alice), N(eosio), asset::from_string("1.0000 EOS"), false );//{ N(alice), N(bob), N(carol) } ); create_account_with_resources( N(alice), N(eosio), asset::from_string("1.0000 EOS"), false );//{ N(alice), N(bob), N(carol) } );
create_account_with_resources( N(bob), N(eosio), asset::from_string("0.4500 EOS"), false );//{ N(alice), N(bob), N(carol) } ); create_account_with_resources( N(bob), N(eosio), asset::from_string("0.4500 EOS"), false );//{ N(alice), N(bob), N(carol) } );
create_account_with_resources( N(carol), N(eosio), asset::from_string("1.0000 EOS"), false );//{ N(alice), N(bob), N(carol) } ); create_account_with_resources( N(carol), N(eosio), asset::from_string("1.0000 EOS"), false );//{ N(alice), N(bob), N(carol) } );
...@@ -313,6 +313,7 @@ BOOST_FIXTURE_TEST_CASE( stake_unstake, eosio_system_tester ) try { ...@@ -313,6 +313,7 @@ BOOST_FIXTURE_TEST_CASE( stake_unstake, eosio_system_tester ) try {
BOOST_REQUIRE_EQUAL( success(), buyram( "alice", "bob", "200.0000 EOS" ) ); BOOST_REQUIRE_EQUAL( success(), buyram( "alice", "bob", "200.0000 EOS" ) );
BOOST_REQUIRE_EQUAL( success(), buyrambytes( "alice", "bob", 100 ) ); BOOST_REQUIRE_EQUAL( success(), buyrambytes( "alice", "bob", 100 ) );
BOOST_REQUIRE_EQUAL( success(), sellram( "bob", 100 ) ); BOOST_REQUIRE_EQUAL( success(), sellram( "bob", 100 ) );
BOOST_REQUIRE_EQUAL( success(), buyrambytes( "alice", "bob", 10000 ) );
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册