1#include <sysio/datastream.hpp>
2#include <sysio/sysio.hpp>
3#include <sysio/multi_index.hpp>
4#include <sysio/privileged.hpp>
5#include <sysio/serialize.hpp>
6#include <sysio/transaction.hpp>
14 using sysio::const_mem_fun;
15 using sysio::current_time_point;
16 using sysio::indexed_by;
27 const int64_t ram_reserve = itr->base.balance.amount;
28 const int64_t eos_reserve = itr->quote.balance.amount;
30 const int64_t cost_plus_fee = cost / double(0.995);
31 buyram( payer, receiver,
asset{ cost_plus_fee, core_symbol() } );
45 require_auth( payer );
48 check( quant.symbol == core_symbol(),
"must buy ram with core token" );
49 check( quant.amount > 0,
"must purchase a positive amount" );
52 fee.amount = ( fee.amount + 199 ) / 200;
56 auto quant_after_fee = quant;
57 quant_after_fee.amount -= fee.amount;
62 transfer_act.send( payer,
ram_account, quant_after_fee,
"buy ram" );
64 if ( fee.amount > 0 ) {
72 const auto& market = _rammarket.get(
ramcore_symbol.raw(),
"ram market does not exist");
73 _rammarket.modify( market, same_payer, [&](
auto& es ) {
74 bytes_out = es.direct_convert( quant_after_fee,
ram_symbol ).amount;
77 check( bytes_out > 0,
"must reserve a positive amount" );
83 auto res_itr = userres.find( receiver.value );
84 if( res_itr == userres.end() ) {
85 res_itr = userres.emplace( receiver, [&](
auto& res ) {
87 res.net_weight =
asset( 0, core_symbol() );
88 res.cpu_weight =
asset( 0, core_symbol() );
89 res.ram_bytes = bytes_out;
92 userres.modify( res_itr, receiver, [&](
auto& res ) {
93 res.ram_bytes += bytes_out;
97 auto voter_itr = _voters.find( res_itr->owner.value );
100 get_resource_limits( res_itr->owner, ram_bytes, net, cpu );
101 set_resource_limits( res_itr->owner, res_itr->ram_bytes + ram_gift_bytes, net, cpu );
112 require_auth( account );
115 check( bytes > 0,
"cannot sell negative byte" );
118 auto res_itr = userres.find( account.value );
119 check( res_itr != userres.end(),
"no resource row" );
120 check( res_itr->ram_bytes >= bytes,
"insufficient quota" );
124 _rammarket.modify( itr, same_payer, [&](
auto& es ) {
126 tokens_out = es.direct_convert(
asset(bytes,
ram_symbol), core_symbol());
129 check( tokens_out.amount > 1,
"token amount received from selling ram is too low" );
135 check( _gstate.
total_ram_stake >= 0,
"error, attempt to unstake more tokens than previously staked" );
137 userres.modify( res_itr, account, [&](
auto& res ) {
138 res.ram_bytes -= bytes;
141 auto voter_itr = _voters.find( res_itr->owner.value );
144 get_resource_limits( res_itr->owner, ram_bytes, net, cpu );
145 set_resource_limits( res_itr->owner, res_itr->ram_bytes + ram_gift_bytes, net, cpu );
152 auto fee = ( tokens_out.amount + 199 ) / 200;
162 const int64_t base_time = 1527811200;
163 const int64_t current_time = 1638921540;
164 const int64_t max_claimable = 100'000'000'0000ll;
165 const int64_t claimable =
int64_t(max_claimable *
double(current_time - base_time) / (10*seconds_per_year) );
167 check( max_claimable - claimable <= stake,
"b1 can only claim their tokens over 10 years" );
170 void system_contract::changebw(
name from,
const name& receiver,
171 const asset& stake_net_delta,
const asset& stake_cpu_delta,
bool transfer )
173 require_auth( from );
174 check( stake_net_delta.amount != 0 || stake_cpu_delta.amount != 0,
"should stake non-zero amount" );
175 check( std::abs( (stake_net_delta + stake_cpu_delta).amount )
176 >= std::max( std::abs( stake_net_delta.amount ), std::abs( stake_cpu_delta.amount ) ),
177 "net and cpu deltas cannot be opposite signs" );
179 name source_stake_from = from;
187 auto itr = del_tbl.find( receiver.value );
188 if( itr == del_tbl.end() ) {
189 itr = del_tbl.emplace( from, [&](
auto& dbo ){
192 dbo.net_weight = stake_net_delta;
193 dbo.cpu_weight = stake_cpu_delta;
197 del_tbl.modify( itr, same_payer, [&](
auto& dbo ){
198 dbo.net_weight += stake_net_delta;
199 dbo.cpu_weight += stake_cpu_delta;
202 check( 0 <= itr->net_weight.amount,
"insufficient staked net bandwidth" );
203 check( 0 <= itr->cpu_weight.amount,
"insufficient staked cpu bandwidth" );
204 if ( itr->is_empty() ) {
205 del_tbl.erase( itr );
212 auto tot_itr = totals_tbl.find( receiver.value );
213 if( tot_itr == totals_tbl.end() ) {
214 tot_itr = totals_tbl.emplace( from, [&](
auto& tot ) {
215 tot.owner = receiver;
216 tot.net_weight = stake_net_delta;
217 tot.cpu_weight = stake_cpu_delta;
220 totals_tbl.modify( tot_itr, from == receiver ? from : same_payer, [&](
auto& tot ) {
221 tot.net_weight += stake_net_delta;
222 tot.cpu_weight += stake_cpu_delta;
225 check( 0 <= tot_itr->net_weight.amount,
"insufficient staked total net bandwidth" );
226 check( 0 <= tot_itr->cpu_weight.amount,
"insufficient staked total cpu bandwidth" );
229 bool ram_managed =
false;
230 bool net_managed =
false;
231 bool cpu_managed =
false;
233 auto voter_itr = _voters.find( receiver.value );
234 if( voter_itr != _voters.end() ) {
240 if( !(net_managed && cpu_managed) ) {
242 get_resource_limits( receiver, ram_bytes, net, cpu );
244 set_resource_limits( receiver,
245 ram_managed ? ram_bytes : std::max( tot_itr->ram_bytes + ram_gift_bytes, ram_bytes ),
246 net_managed ? net : tot_itr->net_weight.amount,
247 cpu_managed ? cpu : tot_itr->cpu_weight.amount );
251 if ( tot_itr->is_empty() ) {
252 totals_tbl.erase( tot_itr );
259 auto req = refunds_tbl.find( from.value );
262 auto net_balance = stake_net_delta;
263 auto cpu_balance = stake_cpu_delta;
264 bool need_deferred_trx =
false;
269 bool is_undelegating = (net_balance.amount + cpu_balance.amount ) < 0;
270 bool is_delegating_to_self = (!transfer && from == receiver);
272 if( is_delegating_to_self || is_undelegating ) {
273 if ( req != refunds_tbl.end() ) {
274 refunds_tbl.modify( req, same_payer, [&]( refund_request&
r ) {
275 if ( net_balance.amount < 0 || cpu_balance.amount < 0 ) {
276 r.request_time = current_time_point();
278 r.net_amount -= net_balance;
279 if (
r.net_amount.amount < 0 ) {
280 net_balance = -
r.net_amount;
281 r.net_amount.amount = 0;
283 net_balance.amount = 0;
285 r.cpu_amount -= cpu_balance;
286 if (
r.cpu_amount.amount < 0 ){
287 cpu_balance = -
r.cpu_amount;
288 r.cpu_amount.amount = 0;
290 cpu_balance.amount = 0;
294 check( 0 <= req->net_amount.amount,
"negative net refund amount" );
295 check( 0 <= req->cpu_amount.amount,
"negative cpu refund amount" );
297 if ( req->is_empty() ) {
298 refunds_tbl.erase( req );
299 need_deferred_trx =
false;
301 need_deferred_trx =
true;
303 }
else if ( net_balance.amount < 0 || cpu_balance.amount < 0 ) {
304 refunds_tbl.emplace( from, [&]( refund_request&
r ) {
306 if ( net_balance.amount < 0 ) {
307 r.net_amount = -net_balance;
308 net_balance.amount = 0;
310 r.net_amount = asset( 0, core_symbol() );
312 if ( cpu_balance.amount < 0 ) {
313 r.cpu_amount = -cpu_balance;
314 cpu_balance.amount = 0;
316 r.cpu_amount = asset( 0, core_symbol() );
318 r.request_time = current_time_point();
320 need_deferred_trx =
true;
324 if ( need_deferred_trx ) {
327 get_self(),
"refund"_n,
330 out.delay_sec = refund_delay_sec;
331 sysio::cancel_deferred( from.value );
332 out.send( from.value, from,
true );
334 sysio::cancel_deferred( from.value );
337 auto transfer_amount = net_balance + cpu_balance;
338 if ( 0 < transfer_amount.amount ) {
340 transfer_act.send( source_stake_from,
stake_account, asset(transfer_amount),
"stake bandwidth" );
344 vote_stake_updater( from );
345 update_voting_power( from, stake_net_delta + stake_cpu_delta );
348 void system_contract::update_voting_power(
const name& voter,
const asset& total_update )
350 auto voter_itr = _voters.find( voter.value );
351 if( voter_itr == _voters.end() ) {
352 voter_itr = _voters.emplace( voter, [&](
auto& v ) {
354 v.staked = total_update.amount;
357 _voters.modify( voter_itr, same_payer, [&](
auto& v ) {
358 v.staked += total_update.amount;
362 check( 0 <= voter_itr->staked,
"stake for voting cannot be negative" );
364 if( voter ==
"b1"_n ) {
368 if( voter_itr->producers.size() || voter_itr->proxy ) {
369 update_votes( voter, voter_itr->proxy, voter_itr->producers,
false );
374 const asset& stake_net_quantity,
375 const asset& stake_cpu_quantity,
bool transfer )
377 asset zero_asset( 0, core_symbol() );
378 check( stake_cpu_quantity >= zero_asset,
"must stake a positive amount" );
379 check( stake_net_quantity >= zero_asset,
"must stake a positive amount" );
380 check( stake_net_quantity.amount + stake_cpu_quantity.amount > 0,
"must stake a positive amount" );
381 check( !transfer || from != receiver,
"cannot use transfer flag if delegating to self" );
383 changebw( from, receiver, stake_net_quantity, stake_cpu_quantity, transfer);
387 const asset& unstake_net_quantity,
const asset& unstake_cpu_quantity )
389 asset zero_asset( 0, core_symbol() );
390 check( unstake_cpu_quantity >= zero_asset,
"must unstake a positive amount" );
391 check( unstake_net_quantity >= zero_asset,
"must unstake a positive amount" );
392 check( unstake_cpu_quantity.amount + unstake_net_quantity.amount > 0,
"must unstake a positive amount" );
394 "cannot undelegate bandwidth until the chain is activated (at least 15% of all tokens participate in voting)" );
396 changebw( from, receiver, -unstake_net_quantity, -unstake_cpu_quantity,
false);
401 require_auth( owner );
404 auto req = refunds_tbl.find( owner.value );
405 check( req != refunds_tbl.end(),
"refund request not found" );
406 check( req->request_time + seconds(refund_delay_sec) <= current_time_point(),
407 "refund is not available yet" );
409 transfer_act.send(
stake_account, req->owner, req->net_amount + req->cpu_amount,
"unstake" );
410 refunds_tbl.erase( req );
sysio::action_wrapper<"transfer"_n, &token::transfer > transfer_action
static constexpr sysio::name ram_account
static constexpr symbol ram_symbol
void buyram(const name &payer, const name &receiver, const asset &quant)
void buyrambytes(const name &payer, const name &receiver, uint32_t bytes)
static constexpr sysio::name stake_account
static constexpr sysio::name token_account
static constexpr sysio::name active_permission
void refund(const name &owner)
void undelegatebw(const name &from, const name &receiver, const asset &unstake_net_quantity, const asset &unstake_cpu_quantity)
static constexpr symbol ramcore_symbol
static constexpr sysio::name ramfee_account
void sellram(const name &account, int64_t bytes)
void delegatebw(const name &from, const name &receiver, const asset &stake_net_quantity, const asset &stake_cpu_quantity, bool transfer)
constexpr microseconds seconds(int64_t s)
sysio::multi_index< "delband"_n, delegated_bandwidth > del_bandwidth_table
sysio::multi_index< "refunds"_n, refund_request > refunds_table
void validate_b1_vesting(int64_t stake)
sysio::multi_index< "userres"_n, user_resources > user_resources_table
unsigned __int64 uint64_t
Immutable except for fc::from_variant.
static int64_t get_bancor_input(int64_t out_reserve, int64_t inp_reserve, int64_t out)
uint64_t total_ram_bytes_reserved
time_point thresh_activated_stake_time