7 using sysio::current_time_point;
13 require_auth( owner );
15 check( amount.symbol == core_symbol(),
"must deposit core token" );
16 check( 0 < amount.amount,
"must deposit a positive amount" );
20 transfer_act.send( owner,
rex_account, amount,
"deposit to REX fund" );
22 transfer_to_fund( owner, amount );
27 require_auth( owner );
29 check( amount.symbol == core_symbol(),
"must withdraw core token" );
30 check( 0 < amount.amount,
"must withdraw a positive amount" );
31 update_rex_account( owner,
asset( 0, core_symbol() ),
asset( 0, core_symbol() ) );
32 transfer_from_fund( owner, amount );
36 transfer_act.send(
rex_account, owner, amount,
"withdraw from REX fund" );
44 check( amount.symbol == core_symbol(),
"asset must be core token" );
45 check( 0 < amount.amount,
"must use positive amount" );
46 check_voting_requirement( from );
47 transfer_from_fund( from, amount );
48 const asset rex_received = add_to_rex_pool( amount );
49 const asset delta_rex_stake = add_to_rex_balance( from, amount, rex_received );
51 update_rex_account( from,
asset( 0, core_symbol() ), delta_rex_stake );
54 buyrex_act.send( rex_received );
59 require_auth( owner );
61 check( from_net.symbol == core_symbol() && from_cpu.symbol == core_symbol(),
"asset must be core token" );
62 check( (0 <= from_net.amount) && (0 <= from_cpu.amount) && (0 < from_net.amount || 0 < from_cpu.amount),
63 "must unstake a positive amount to buy rex" );
64 check_voting_requirement( owner );
68 auto del_itr = dbw_table.require_find( receiver.value,
"delegated bandwidth record does not exist" );
69 check( from_net.amount <= del_itr->net_weight.amount,
"amount exceeds tokens staked for net");
70 check( from_cpu.amount <= del_itr->cpu_weight.amount,
"amount exceeds tokens staked for cpu");
75 if ( del_itr->is_empty() ) {
76 dbw_table.erase( del_itr );
80 update_resource_limits(
name(0), receiver, -from_net.amount, -from_cpu.amount );
82 const asset payment = from_net + from_cpu;
88 const asset rex_received = add_to_rex_pool( payment );
89 auto rex_stake_delta = add_to_rex_balance( owner, payment, rex_received );
91 update_rex_account( owner,
asset( 0, core_symbol() ), rex_stake_delta - payment,
true );
94 buyrex_act.send( rex_received );
103 auto bitr = _rexbalance.require_find( from.value,
"user must first buyrex" );
104 check( rex.amount > 0 && rex.symbol == bitr->rex_balance.symbol,
105 "asset must be a positive amount of (REX, 4)" );
106 process_rex_maturities( bitr );
107 check( rex.amount <= bitr->matured_rex,
"insufficient available rex" );
109 const auto current_order = fill_rex_order( bitr, rex );
110 if ( current_order.success && current_order.proceeds.amount == 0 ) {
111 check(
false,
"proceeds are negligible" );
113 asset pending_sell_order = update_rex_account( from, current_order.proceeds, current_order.stake_change );
114 if ( !current_order.success ) {
115 if ( from ==
"b1"_n ) {
116 check(
false,
"b1 sellrex orders should not be queued" );
122 auto oitr = _rexorders.find( from.value );
123 if ( oitr == _rexorders.end() ) {
124 oitr = _rexorders.emplace( from, [&](
auto& order ) {
126 order.rex_requested = rex;
127 order.is_open =
true;
128 order.proceeds =
asset( 0, core_symbol() );
129 order.stake_change =
asset( 0, core_symbol() );
130 order.order_time = current_time_point();
133 _rexorders.modify( oitr, same_payer, [&](
auto& order ) {
134 order.rex_requested.amount += rex.amount;
137 pending_sell_order.amount = oitr->rex_requested.amount;
139 check( pending_sell_order.amount <= bitr->matured_rex,
"insufficient funds for current and scheduled orders" );
141 if ( current_order.success ) {
143 sellrex_act.send( current_order.proceeds );
149 require_auth( owner );
151 auto itr = _rexorders.require_find( owner.value,
"no sellrex order is scheduled" );
152 check( itr->is_open,
"sellrex order has been filled and cannot be canceled" );
153 _rexorders.erase( itr );
158 require_auth( from );
161 int64_t rented_tokens = rent_rex( cpu_loans, from, receiver, loan_payment, loan_fund );
162 update_resource_limits( from, receiver, 0, rented_tokens );
167 require_auth( from );
170 int64_t rented_tokens = rent_rex( net_loans, from, receiver, loan_payment, loan_fund );
171 update_resource_limits( from, receiver, rented_tokens, 0 );
176 require_auth( from );
179 fund_rex_loan( cpu_loans, from, loan_num, payment );
184 require_auth( from );
187 fund_rex_loan( net_loans, from, loan_num, payment );
192 require_auth( from );
195 defund_rex_loan( cpu_loans, from, loan_num, amount );
200 require_auth( from );
203 defund_rex_loan( net_loans, from, loan_num, amount );
208 require_auth( owner );
212 auto itr = _rexbalance.require_find( owner.value,
"account has no REX balance" );
213 const asset init_stake = itr->vote_stake;
215 auto rexpool_itr = _rexpool.begin();
216 const int64_t total_rex = rexpool_itr->total_rex.amount;
217 const int64_t total_lendable = rexpool_itr->total_lendable.amount;
220 asset current_stake( 0, core_symbol() );
221 if ( total_rex > 0 ) {
222 current_stake.amount = ( uint128_t(
rex_balance) * total_lendable ) / total_rex;
224 _rexbalance.modify( itr, same_payer, [&](
auto& rb ) {
225 rb.vote_stake = current_stake;
228 update_rex_account( owner,
asset( 0, core_symbol() ), current_stake - init_stake,
true );
229 process_rex_maturities( itr );
234 require_auth(
"sysio"_n );
236 check( balance.amount > 0,
"balance must be set to have a positive amount" );
237 check( balance.symbol == core_symbol(),
"balance symbol must be core symbol" );
238 check( rex_system_initialized(),
"rex system is not initialized" );
239 _rexpool.modify( _rexpool.begin(), same_payer, [&](
auto& pool ) {
240 pool.total_rent = balance;
246 require_auth( user );
253 require_auth( owner );
257 auto bitr = _rexbalance.require_find( owner.value,
"account has no REX balance" );
258 asset rex_in_sell_order = update_rex_account( owner,
asset( 0, core_symbol() ),
asset( 0, core_symbol() ) );
259 consolidate_rex_balance( bitr, rex_in_sell_order );
264 require_auth( owner );
268 auto bitr = _rexbalance.require_find( owner.value,
"account has no REX balance" );
269 check( rex.amount > 0 && rex.symbol == bitr->rex_balance.symbol,
"asset must be a positive amount of (REX, 4)" );
270 const asset rex_in_sell_order = update_rex_account( owner,
asset( 0, core_symbol() ),
asset( 0, core_symbol() ) );
271 const int64_t rex_in_savings = read_rex_savings( bitr );
272 check( rex.amount + rex_in_sell_order.amount + rex_in_savings <= bitr->
rex_balance.amount,
273 "insufficient REX balance" );
274 process_rex_maturities( bitr );
275 _rexbalance.modify( bitr, same_payer, [&](
auto& rb ) {
277 while ( !rb.rex_maturities.empty() && moved_rex < rex.amount) {
278 const int64_t d_rex = std::min( rex.amount - moved_rex, rb.rex_maturities.back().second );
279 rb.rex_maturities.back().second -= d_rex;
281 if ( rb.rex_maturities.back().second == 0 ) {
282 rb.rex_maturities.pop_back();
285 if ( moved_rex < rex.amount ) {
286 const int64_t d_rex = rex.amount - moved_rex;
287 rb.matured_rex -= d_rex;
289 check( rex_in_sell_order.amount <= rb.matured_rex,
"logic error in mvtosavings" );
291 check( moved_rex == rex.amount,
"programmer error in mvtosavings" );
293 put_rex_savings( bitr, rex_in_savings + rex.amount );
298 require_auth( owner );
302 auto bitr = _rexbalance.require_find( owner.value,
"account has no REX balance" );
303 check( rex.amount > 0 && rex.symbol == bitr->rex_balance.symbol,
"asset must be a positive amount of (REX, 4)" );
304 const int64_t rex_in_savings = read_rex_savings( bitr );
305 check( rex.amount <= rex_in_savings,
"insufficient REX in savings" );
306 process_rex_maturities( bitr );
307 _rexbalance.modify( bitr, same_payer, [&](
auto& rb ) {
309 if ( !rb.rex_maturities.empty() && rb.rex_maturities.back().first == maturity ) {
310 rb.rex_maturities.back().second += rex.amount;
315 put_rex_savings( bitr, rex_in_savings - rex.amount );
316 update_rex_account( owner,
asset( 0, core_symbol() ),
asset( 0, core_symbol() ) );
321 require_auth( owner );
323 if ( rex_system_initialized() )
326 update_rex_account( owner,
asset( 0, core_symbol() ),
asset( 0, core_symbol() ) );
331 auto cpu_idx = cpu_loans.get_index<
"byowner"_n>();
332 bool no_outstanding_cpu_loans = ( cpu_idx.find( owner.value ) == cpu_idx.end() );
335 auto net_idx = net_loans.get_index<
"byowner"_n>();
336 bool no_outstanding_net_loans = ( net_idx.find( owner.value ) == net_idx.end() );
338 auto fund_itr = _rexfunds.find( owner.value );
339 bool no_outstanding_rex_fund = ( fund_itr != _rexfunds.end() ) && ( fund_itr->balance.amount == 0 );
341 if ( no_outstanding_cpu_loans && no_outstanding_net_loans && no_outstanding_rex_fund ) {
342 _rexfunds.erase( fund_itr );
348 auto rex_itr = _rexbalance.find( owner.value );
349 if ( rex_itr != _rexbalance.end() ) {
350 check( rex_itr->rex_balance.amount == 0,
"account has remaining REX balance, must sell first");
351 _rexbalance.erase( rex_itr );
364 void system_contract::update_resource_limits(
const name& from,
const name& receiver,
int64_t delta_net,
int64_t delta_cpu )
366 if ( delta_cpu == 0 && delta_net == 0 ) {
371 auto tot_itr = totals_tbl.find( receiver.value );
372 if ( tot_itr == totals_tbl.end() ) {
373 check( 0 <= delta_net && 0 <= delta_cpu,
"logic error, should not occur");
374 tot_itr = totals_tbl.emplace( from, [&](
auto& tot ) {
375 tot.owner = receiver;
376 tot.net_weight =
asset( delta_net, core_symbol() );
377 tot.cpu_weight =
asset( delta_cpu, core_symbol() );
380 totals_tbl.modify( tot_itr, same_payer, [&](
auto& tot ) {
381 tot.net_weight.amount += delta_net;
382 tot.cpu_weight.amount += delta_cpu;
385 check( 0 <= tot_itr->net_weight.amount,
"insufficient staked total net bandwidth" );
386 check( 0 <= tot_itr->cpu_weight.amount,
"insufficient staked total cpu bandwidth" );
389 bool net_managed =
false;
390 bool cpu_managed =
false;
392 auto voter_itr = _voters.find( receiver.value );
393 if( voter_itr != _voters.end() ) {
398 if( !(net_managed && cpu_managed) ) {
399 int64_t ram_bytes = 0, net = 0, cpu = 0;
400 get_resource_limits( receiver, ram_bytes, net, cpu );
402 set_resource_limits( receiver,
404 net_managed ? net : tot_itr->net_weight.amount,
405 cpu_managed ? cpu : tot_itr->cpu_weight.amount );
409 if ( tot_itr->is_empty() ) {
410 totals_tbl.erase( tot_itr );
421 void system_contract::check_voting_requirement(
const name& owner,
const char* error_msg )
const
423 auto vitr = _voters.find( owner.value );
424 check( vitr != _voters.end() && ( vitr->proxy || 21 <= vitr->producers.size() ), error_msg );
433 bool system_contract::rex_loans_available()
const
435 if ( !rex_available() ) {
438 if ( _rexorders.begin() == _rexorders.end() ) {
441 auto idx = _rexorders.get_index<
"bytime"_n>();
442 return !idx.begin()->is_open;
454 void system_contract::add_loan_to_rex_pool(
const asset& payment,
int64_t rented_tokens,
bool new_loan )
456 add_to_rex_return_pool( payment );
457 _rexpool.modify( _rexpool.begin(), same_payer, [&](
auto& rt ) {
459 rt.total_rent.amount += payment.amount;
461 rt.total_unlent.amount -= rented_tokens;
462 rt.total_lent.amount += rented_tokens;
475 void system_contract::remove_loan_from_rex_pool(
const rex_loan& loan )
477 const auto& pool = _rexpool.begin();
478 const int64_t delta_total_rent = exchange_state::get_bancor_output( pool->total_unlent.amount,
479 pool->total_rent.amount,
480 loan.total_staked.amount );
481 _rexpool.modify( pool, same_payer, [&](
auto& rt ) {
483 rt.total_rent.amount -= delta_total_rent;
485 rt.total_unlent.amount += loan.total_staked.amount;
486 rt.total_lent.amount -= loan.total_staked.amount;
487 rt.total_lendable.amount = rt.total_unlent.amount + rt.total_lent.amount;
494 template <
typename Index,
typename Iterator>
495 int64_t system_contract::update_renewed_loan( Index& idx,
const Iterator& itr,
int64_t rented_tokens )
497 int64_t delta_stake = rented_tokens - itr->total_staked.amount;
498 idx.modify ( itr, same_payer, [&](
auto& loan ) {
499 loan.total_staked.amount = rented_tokens;
501 loan.balance.amount -= loan.payment.amount;
511 void system_contract::runrex(
uint16_t max )
513 check( rex_system_initialized(),
"rex system not initialized yet" );
517 const auto& pool = _rexpool.begin();
519 auto process_expired_loan = [&](
auto& idx,
const auto& itr ) -> std::pair<bool, int64_t> {
521 remove_loan_from_rex_pool( *itr );
522 bool delete_loan =
false;
525 int64_t rented_tokens = exchange_state::get_bancor_output( pool->total_rent.amount,
526 pool->total_unlent.amount,
527 itr->payment.amount );
529 bool renew_loan = itr->payment <= itr->balance
530 && itr->payment.amount < rented_tokens
531 && rex_loans_available();
534 add_loan_to_rex_pool( itr->payment, rented_tokens,
false );
536 delta_stake = update_renewed_loan( idx, itr, rented_tokens );
539 delta_stake = -( itr->total_staked.amount );
541 if ( itr->balance.amount > 0 ) {
542 transfer_to_fund( itr->from, itr->balance );
546 return { delete_loan, delta_stake };
550 if ( pool->namebid_proceeds.amount > 0 ) {
551 channel_to_rex( names_account, pool->namebid_proceeds );
552 _rexpool.modify( pool, same_payer, [&](
auto& rt ) {
553 rt.namebid_proceeds.amount = 0;
560 auto cpu_idx = cpu_loans.get_index<
"byexpr"_n>();
561 for (
uint16_t i = 0; i < max; ++i ) {
562 auto itr = cpu_idx.begin();
563 if ( itr == cpu_idx.end() || itr->expiration > current_time_point() )
break;
565 auto result = process_expired_loan( cpu_idx, itr );
566 if ( result.second != 0 )
567 update_resource_limits( itr->from, itr->receiver, 0, result.second );
570 cpu_idx.erase( itr );
577 auto net_idx = net_loans.get_index<
"byexpr"_n>();
578 for (
uint16_t i = 0; i < max; ++i ) {
579 auto itr = net_idx.begin();
580 if ( itr == net_idx.end() || itr->expiration > current_time_point() )
break;
582 auto result = process_expired_loan( net_idx, itr );
583 if ( result.second != 0 )
584 update_resource_limits( itr->from, itr->receiver, result.second, 0 );
587 net_idx.erase( itr );
592 if ( _rexorders.begin() != _rexorders.end() ) {
593 auto idx = _rexorders.get_index<
"bytime"_n>();
594 auto oitr = idx.begin();
595 for (
uint16_t i = 0; i < max; ++i ) {
596 if ( oitr == idx.end() || !oitr->is_open )
break;
599 auto bitr = _rexbalance.find( oitr->owner.value );
600 if ( bitr != _rexbalance.end() ) {
601 auto result = fill_rex_order( bitr, oitr->rex_requested );
602 if ( result.success ) {
603 const name order_owner = oitr->owner;
604 idx.modify( oitr, same_payer, [&](
auto& order ) {
605 order.proceeds.amount = result.proceeds.amount;
606 order.stake_change.amount = result.stake_change.amount;
611 order_act.send( order_owner, result.proceeds );
623 void system_contract::update_rex_pool()
625 auto get_elapsed_intervals = [&](
const time_point_sec& t1,
const time_point_sec& t0 ) ->
uint32_t {
626 return ( t1.sec_since_epoch() - t0.sec_since_epoch() ) / rex_return_pool::dist_interval;
629 const time_point_sec ct = current_time_point();
630 const uint32_t cts = ct.sec_since_epoch();
631 const time_point_sec effective_time{cts - cts % rex_return_pool::dist_interval};
633 const auto ret_pool_elem = _rexretpool.begin();
634 const auto ret_buckets_elem = _rexretbuckets.begin();
636 if ( ret_pool_elem == _rexretpool.end() || effective_time <= ret_pool_elem->last_dist_time ) {
640 const int64_t current_rate = ret_pool_elem->current_rate_of_increase;
641 const uint32_t elapsed_intervals = get_elapsed_intervals( effective_time, ret_pool_elem->last_dist_time );
642 int64_t change_estimate = current_rate * elapsed_intervals;
645 const bool new_return_bucket = ret_pool_elem->pending_bucket_time <= effective_time;
647 time_point_sec new_bucket_time = time_point_sec::min();
648 _rexretpool.modify( ret_pool_elem, same_payer, [&](
auto& rp ) {
649 if ( new_return_bucket ) {
650 int64_t remainder = rp.pending_bucket_proceeds % rex_return_pool::total_intervals;
651 new_bucket_rate = ( rp.pending_bucket_proceeds - remainder ) / rex_return_pool::total_intervals;
652 new_bucket_time = rp.pending_bucket_time;
653 rp.current_rate_of_increase += new_bucket_rate;
654 change_estimate += remainder + new_bucket_rate * get_elapsed_intervals( effective_time, rp.pending_bucket_time );
655 rp.pending_bucket_proceeds = 0;
656 rp.pending_bucket_time = time_point_sec::maximum();
657 if ( new_bucket_time < rp.oldest_bucket_time ) {
658 rp.oldest_bucket_time = new_bucket_time;
661 rp.proceeds -= change_estimate;
662 rp.last_dist_time = effective_time;
665 if ( new_return_bucket ) {
666 _rexretbuckets.modify( ret_buckets_elem, same_payer, [&](
auto& rb ) {
667 auto iter = std::lower_bound(rb.return_buckets.begin(), rb.return_buckets.end(), new_bucket_time, [](
const pair_time_point_sec_int64& bucket, time_point_sec first) {
668 return bucket.first < first;
670 if ((iter != rb.return_buckets.end()) && (iter->first == new_bucket_time)) {
671 iter->second = new_bucket_rate;
673 rb.return_buckets.insert(iter, pair_time_point_sec_int64{new_bucket_time, new_bucket_rate});
679 const time_point_sec time_threshold = effective_time - seconds(rex_return_pool::total_intervals * rex_return_pool::dist_interval);
680 if ( ret_pool_elem->oldest_bucket_time <= time_threshold ) {
683 _rexretbuckets.modify( ret_buckets_elem, same_payer, [&](
auto& rb ) {
684 auto& return_buckets = rb.return_buckets;
685 auto iter = return_buckets.begin();
686 for (; iter != return_buckets.end() && iter->first <= time_threshold; ++iter) {
687 const uint32_t overtime = get_elapsed_intervals( effective_time,
688 iter->first + seconds(rex_return_pool::total_intervals * rex_return_pool::dist_interval) );
689 surplus += iter->second * overtime;
690 expired_rate += iter->second;
692 return_buckets.erase(return_buckets.begin(), iter);
695 _rexretpool.modify( ret_pool_elem, same_payer, [&](
auto& rp ) {
696 if ( !ret_buckets_elem->return_buckets.empty() ) {
697 rp.oldest_bucket_time = ret_buckets_elem->return_buckets.begin()->first;
699 rp.oldest_bucket_time = time_point_sec::min();
701 if ( expired_rate > 0) {
702 rp.current_rate_of_increase -= expired_rate;
705 change_estimate -= surplus;
706 rp.proceeds += surplus;
711 if ( change_estimate > 0 && ret_pool_elem->proceeds < 0 ) {
712 _rexretpool.modify( ret_pool_elem, same_payer, [&](
auto& rp ) {
713 change_estimate += rp.proceeds;
718 if ( change_estimate > 0 ) {
719 _rexpool.modify( _rexpool.begin(), same_payer, [&](
auto& pool ) {
720 pool.total_unlent.amount += change_estimate;
721 pool.total_lendable = pool.total_unlent + pool.total_lent;
726 template <
typename T>
727 int64_t system_contract::rent_rex(
T& table,
const name& from,
const name& receiver,
const asset& payment,
const asset& fund )
731 check( rex_loans_available(),
"rex loans are currently not available" );
732 check( payment.symbol == core_symbol() && fund.symbol == core_symbol(),
"must use core token" );
733 check( 0 < payment.amount && 0 <= fund.amount,
"must use positive asset amount" );
735 transfer_from_fund( from, payment + fund );
737 const auto& pool = _rexpool.begin();
739 int64_t rented_tokens = exchange_state::get_bancor_output( pool->total_rent.amount,
740 pool->total_unlent.amount,
742 check( payment.amount < rented_tokens,
"loan price does not favor renting" );
743 add_loan_to_rex_pool( payment, rented_tokens,
true );
745 table.emplace( from, [&](
auto& c ) {
747 c.receiver = receiver;
750 c.total_staked =
asset( rented_tokens, core_symbol() );
751 c.expiration = current_time_point() +
sysio::days(30);
752 c.loan_num = pool->loan_num;
756 rentresult_act.send(
asset{ rented_tokens, core_symbol() } );
757 return rented_tokens;
776 rex_order_outcome system_contract::fill_rex_order(
const rex_balance_table::const_iterator& bitr,
const asset& rex )
778 auto rexpool_itr = _rexpool.begin();
779 const int64_t S0 = rexpool_itr->total_lendable.amount;
780 const int64_t R0 = rexpool_itr->total_rex.amount;
782 const int64_t R1 = R0 - rex.amount;
784 asset proceeds(
p, core_symbol() );
785 asset stake_change( 0, core_symbol() );
788 const int64_t unlent_lower_bound = rexpool_itr->total_lent.amount / 10;
789 const int64_t available_unlent = rexpool_itr->total_unlent.amount - unlent_lower_bound;
790 if ( proceeds.amount <= available_unlent ) {
791 const int64_t init_vote_stake_amount = bitr->vote_stake.amount;
792 const int64_t current_stake_value = (
uint128_t(bitr->rex_balance.amount) * S0 ) / R0;
793 _rexpool.modify( rexpool_itr, same_payer, [&](
auto& rt ) {
794 rt.total_rex.amount = R1;
795 rt.total_lendable.amount = S1;
796 rt.total_unlent.amount = rt.total_lendable.amount - rt.total_lent.amount;
798 _rexbalance.modify( bitr, same_payer, [&](
auto& rb ) {
799 rb.vote_stake.amount = current_stake_value - proceeds.amount;
800 rb.rex_balance.amount -= rex.amount;
801 rb.matured_rex -= rex.amount;
803 stake_change.amount = bitr->vote_stake.amount - init_vote_stake_amount;
809 return {
success, proceeds, stake_change };
812 template <
typename T>
813 void system_contract::fund_rex_loan(
T& table,
const name& from,
uint64_t loan_num,
const asset& payment )
815 check( payment.symbol == core_symbol(),
"must use core token" );
816 transfer_from_fund( from, payment );
817 auto itr = table.require_find( loan_num,
"loan not found" );
818 check( itr->from == from,
"user must be loan creator" );
819 check( itr->expiration > current_time_point(),
"loan has already expired" );
820 table.modify( itr, same_payer, [&](
auto& loan ) {
821 loan.balance.amount += payment.amount;
825 template <
typename T>
826 void system_contract::defund_rex_loan(
T& table,
const name& from,
uint64_t loan_num,
const asset& amount )
828 check( amount.symbol == core_symbol(),
"must use core token" );
829 auto itr = table.require_find( loan_num,
"loan not found" );
830 check( itr->from == from,
"user must be loan creator" );
831 check( itr->expiration > current_time_point(),
"loan has already expired" );
832 check( itr->balance >= amount,
"insufficent loan balance" );
833 table.modify( itr, same_payer, [&](
auto& loan ) {
834 loan.balance.amount -= amount.amount;
836 transfer_to_fund( from, amount );
847 void system_contract::transfer_from_fund(
const name& owner,
const asset& amount )
849 check( 0 < amount.amount && amount.symbol == core_symbol(),
"must transfer positive amount from REX fund" );
850 auto itr = _rexfunds.require_find( owner.value,
"must deposit to REX fund first" );
851 check( amount <= itr->balance,
"insufficient funds" );
852 _rexfunds.modify( itr, same_payer, [&](
auto& fund ) {
853 fund.balance.amount -= amount.amount;
863 void system_contract::transfer_to_fund(
const name& owner,
const asset& amount )
865 check( 0 < amount.amount && amount.symbol == core_symbol(),
"must transfer positive amount to REX fund" );
866 auto itr = _rexfunds.find( owner.value );
867 if ( itr == _rexfunds.end() ) {
868 _rexfunds.emplace( owner, [&](
auto& fund ) {
870 fund.balance = amount;
873 _rexfunds.modify( itr, same_payer, [&](
auto& fund ) {
874 fund.balance.amount += amount.amount;
894 asset system_contract::update_rex_account(
const name& owner,
const asset& proceeds,
const asset& delta_stake,
bool force_vote_update )
896 asset to_fund( proceeds );
897 asset to_stake( delta_stake );
898 asset rex_in_sell_order( 0, rex_symbol );
899 auto itr = _rexorders.find( owner.value );
900 if ( itr != _rexorders.end() ) {
901 if ( itr->is_open ) {
902 rex_in_sell_order.amount = itr->rex_requested.amount;
904 to_fund.amount += itr->proceeds.amount;
905 to_stake.amount += itr->stake_change.amount;
906 _rexorders.erase( itr );
910 if ( to_fund.amount > 0 )
911 transfer_to_fund( owner, to_fund );
912 if ( force_vote_update || to_stake.amount != 0 )
913 update_voting_power( owner, to_stake );
915 return rex_in_sell_order;
925 void system_contract::channel_to_rex(
const name& from,
const asset& amount,
bool required )
927#if CHANNEL_RAM_AND_NAMEBID_FEES_TO_REX
928 if ( rex_available() ) {
929 add_to_rex_return_pool( amount );
931 token::transfer_action transfer_act{ token_account, { from, active_permission } };
932 transfer_act.send( from, rex_account, amount,
933 std::string(
"transfer from ") + from.to_string() +
" to sysio.rex" );
937 sysio::check( !required,
"can't channel fees to rex" );
945 void system_contract::channel_namebid_to_rex(
const int64_t highest_bid )
947#if CHANNEL_RAM_AND_NAMEBID_FEES_TO_REX
948 if ( rex_available() ) {
949 _rexpool.modify( _rexpool.begin(), same_payer, [&](
auto& rp ) {
950 rp.namebid_proceeds.amount += highest_bid;
962 time_point_sec system_contract::get_rex_maturity()
964 const uint32_t num_of_maturity_buckets = 5;
965 static const uint32_t now = current_time_point().sec_since_epoch();
966 static const uint32_t r = now % seconds_per_day;
967 static const time_point_sec rms{ now -
r + num_of_maturity_buckets * seconds_per_day };
976 void system_contract::process_rex_maturities(
const rex_balance_table::const_iterator& bitr )
978 const time_point_sec now = current_time_point();
979 _rexbalance.modify( bitr, same_payer, [&](
auto& rb ) {
980 while ( !rb.rex_maturities.empty() && rb.rex_maturities.front().first <= now ) {
981 rb.matured_rex += rb.rex_maturities.front().second;
982 rb.rex_maturities.erase(rb.rex_maturities.begin());
993 void system_contract::consolidate_rex_balance(
const rex_balance_table::const_iterator& bitr,
994 const asset& rex_in_sell_order )
996 const int64_t rex_in_savings = read_rex_savings( bitr );
997 _rexbalance.modify( bitr, same_payer, [&](
auto& rb ) {
998 int64_t total = rb.matured_rex - rex_in_sell_order.amount;
999 rb.matured_rex = rex_in_sell_order.amount;
1000 while ( !rb.rex_maturities.empty() ) {
1001 total += rb.rex_maturities.front().second;
1002 rb.rex_maturities.erase(rb.rex_maturities.begin());
1005 rb.rex_maturities.emplace_back( pair_time_point_sec_int64{ get_rex_maturity(), total } );
1008 put_rex_savings( bitr, rex_in_savings );
1018 asset system_contract::add_to_rex_pool(
const asset& payment )
1028 const int64_t rex_ratio = 10000;
1029 const asset init_total_rent( 20'000'0000, core_symbol() );
1030 asset rex_received( 0, rex_symbol );
1031 auto itr = _rexpool.begin();
1032 if ( !rex_system_initialized() ) {
1034 _rexpool.emplace( get_self(), [&](
auto& rp ) {
1035 rex_received.amount = payment.amount * rex_ratio;
1036 rp.total_lendable = payment;
1037 rp.total_lent =
asset( 0, core_symbol() );
1038 rp.total_unlent = rp.total_lendable - rp.total_lent;
1039 rp.total_rent = init_total_rent;
1040 rp.total_rex = rex_received;
1041 rp.namebid_proceeds =
asset( 0, core_symbol() );
1043 }
else if ( !rex_available() ) {
1044 _rexpool.modify( itr, same_payer, [&](
auto& rp ) {
1045 rex_received.amount = payment.amount * rex_ratio;
1046 rp.total_lendable.amount = payment.amount;
1047 rp.total_lent.amount = 0;
1048 rp.total_unlent.amount = rp.total_lendable.amount - rp.total_lent.amount;
1049 rp.total_rent.amount = init_total_rent.amount;
1050 rp.total_rex.amount = rex_received.amount;
1054 check( itr->total_lendable.amount > 0,
"lendable REX pool is empty" );
1055 const int64_t S0 = itr->total_lendable.amount;
1056 const int64_t S1 = S0 + payment.amount;
1057 const int64_t R0 = itr->total_rex.amount;
1059 rex_received.amount = R1 - R0;
1060 _rexpool.modify( itr, same_payer, [&](
auto& rp ) {
1061 rp.total_lendable.amount = S1;
1062 rp.total_rex.amount = R1;
1063 rp.total_unlent.amount = rp.total_lendable.amount - rp.total_lent.amount;
1064 check( rp.total_unlent.amount >= 0,
"programmer error, this should never go negative" );
1068 return rex_received;
1076 void system_contract::add_to_rex_return_pool(
const asset& fee )
1079 if ( fee.amount <= 0 ) {
1083 const time_point_sec ct = current_time_point();
1084 const uint32_t cts = ct.sec_since_epoch();
1085 const uint32_t bucket_interval = rex_return_pool::hours_per_bucket * seconds_per_hour;
1086 const time_point_sec effective_time{cts - cts % bucket_interval + bucket_interval};
1087 const auto return_pool_elem = _rexretpool.begin();
1088 if ( return_pool_elem == _rexretpool.end() ) {
1089 _rexretpool.emplace( get_self(), [&](
auto& rp ) {
1090 rp.last_dist_time = effective_time;
1091 rp.pending_bucket_proceeds = fee.amount;
1092 rp.pending_bucket_time = effective_time;
1093 rp.proceeds = fee.amount;
1095 _rexretbuckets.emplace( get_self(), [&](
auto& rb ) { } );
1097 _rexretpool.modify( return_pool_elem, same_payer, [&](
auto& rp ) {
1098 rp.pending_bucket_proceeds += fee.amount;
1099 rp.proceeds += fee.amount;
1100 if ( rp.pending_bucket_time == time_point_sec::maximum() ) {
1101 rp.pending_bucket_time = effective_time;
1116 asset system_contract::add_to_rex_balance(
const name& owner,
const asset& payment,
const asset& rex_received )
1118 asset init_rex_stake( 0, core_symbol() );
1119 asset current_rex_stake( 0, core_symbol() );
1120 auto bitr = _rexbalance.find( owner.value );
1121 if ( bitr == _rexbalance.end() ) {
1122 bitr = _rexbalance.emplace( owner, [&](
auto& rb ) {
1124 rb.vote_stake = payment;
1125 rb.rex_balance = rex_received;
1127 current_rex_stake.amount = payment.amount;
1129 init_rex_stake.amount = bitr->vote_stake.amount;
1130 _rexbalance.modify( bitr, same_payer, [&](
auto& rb ) {
1131 rb.rex_balance.amount += rex_received.amount;
1132 rb.vote_stake.amount = (
uint128_t(rb.rex_balance.amount) * _rexpool.begin()->total_lendable.amount )
1133 / _rexpool.begin()->total_rex.amount;
1135 current_rex_stake.amount = bitr->vote_stake.amount;
1138 const int64_t rex_in_savings = read_rex_savings( bitr );
1139 process_rex_maturities( bitr );
1140 _rexbalance.modify( bitr, same_payer, [&](
auto& rb ) {
1141 const time_point_sec maturity = get_rex_maturity();
1142 if ( !rb.rex_maturities.empty() && rb.rex_maturities.back().first == maturity ) {
1143 rb.rex_maturities.back().second += rex_received.amount;
1145 rb.rex_maturities.emplace_back( pair_time_point_sec_int64 { maturity, rex_received.amount } );
1148 put_rex_savings( bitr, rex_in_savings );
1149 return current_rex_stake - init_rex_stake;
1163 int64_t system_contract::read_rex_savings(
const rex_balance_table::const_iterator& bitr )
1166 static const time_point_sec end_of_days = time_point_sec::maximum();
1167 if ( !bitr->rex_maturities.empty() && bitr->rex_maturities.back().first == end_of_days ) {
1168 _rexbalance.modify( bitr, same_payer, [&](
auto& rb ) {
1169 rex_in_savings = rb.rex_maturities.back().second;
1170 rb.rex_maturities.pop_back();
1173 return rex_in_savings;
1182 void system_contract::put_rex_savings(
const rex_balance_table::const_iterator& bitr,
int64_t rex )
1184 if ( rex == 0 )
return;
1185 static const time_point_sec end_of_days = time_point_sec::maximum();
1186 _rexbalance.modify( bitr, same_payer, [&](
auto& rb ) {
1187 if ( !rb.rex_maturities.empty() && rb.rex_maturities.back().first == end_of_days ) {
1188 rb.rex_maturities.back().second += rex;
1190 rb.rex_maturities.emplace_back( pair_time_point_sec_int64{ end_of_days, rex } );
1200 void system_contract::update_rex_stake(
const name& voter )
1203 auto bitr = _rexbalance.find( voter.value );
1204 if ( bitr != _rexbalance.end() && rex_available() ) {
1205 asset init_vote_stake = bitr->vote_stake;
1206 asset current_vote_stake( 0, core_symbol() );
1207 current_vote_stake.amount = (
uint128_t(bitr->rex_balance.amount) * _rexpool.begin()->total_lendable.amount )
1208 / _rexpool.begin()->total_rex.amount;
1209 _rexbalance.modify( bitr, same_payer, [&](
auto& rb ) {
1210 rb.vote_stake.amount = current_vote_stake.amount;
1212 delta_stake = current_vote_stake.amount - init_vote_stake.amount;
1215 if ( delta_stake != 0 ) {
1216 auto vitr = _voters.find( voter.value );
1217 if ( vitr != _voters.end() ) {
1218 _voters.modify( vitr, same_payer, [&](
auto& vinfo ) {
1219 vinfo.staked += delta_stake;
action_wrapper<"sellresult"_n, &rex_results::sellresult > sellresult_action
action_wrapper<"rentresult"_n, &rex_results::rentresult > rentresult_action
action_wrapper<"orderresult"_n, &rex_results::orderresult > orderresult_action
action_wrapper<"buyresult"_n, &rex_results::buyresult > buyresult_action
sysio::action_wrapper<"transfer"_n, &token::transfer > transfer_action
void mvfrsavings(const name &owner, const asset &rex)
void mvtosavings(const name &owner, const asset &rex)
void deposit(const name &owner, const asset &amount)
void setrex(const asset &balance)
void fundcpuloan(const name &from, uint64_t loan_num, const asset &payment)
void rentnet(const name &from, const name &receiver, const asset &loan_payment, const asset &loan_fund)
void unstaketorex(const name &owner, const name &receiver, const asset &from_net, const asset &from_cpu)
void rentcpu(const name &from, const name &receiver, const asset &loan_payment, const asset &loan_fund)
static constexpr sysio::name stake_account
static constexpr sysio::name token_account
void cnclrexorder(const name &owner)
static constexpr sysio::name active_permission
void consolidate(const name &owner)
void updaterex(const name &owner)
void sellrex(const name &from, const asset &rex)
void rexexec(const name &user, uint16_t max)
void buyrex(const name &from, const asset &amount)
void closerex(const name &owner)
static constexpr sysio::name rex_account
void fundnetloan(const name &from, uint64_t loan_num, const asset &payment)
void withdraw(const name &owner, const asset &amount)
void defcpuloan(const name &from, uint64_t loan_num, const asset &amount)
void defnetloan(const name &from, uint64_t loan_num, const asset &amount)
constexpr microseconds seconds(int64_t s)
constexpr microseconds days(int64_t d)
sysio::multi_index< "delband"_n, delegated_bandwidth > del_bandwidth_table
sysio::multi_index< "cpuloan"_n, rex_loan, indexed_by<"byexpr"_n, const_mem_fun< rex_loan, uint64_t, &rex_loan::by_expr > >, indexed_by<"byowner"_n, const_mem_fun< rex_loan, uint64_t, &rex_loan::by_owner > > > rex_cpu_loan_table
sysio::multi_index< "netloan"_n, rex_loan, indexed_by<"byexpr"_n, const_mem_fun< rex_loan, uint64_t, &rex_loan::by_expr > >, indexed_by<"byowner"_n, const_mem_fun< rex_loan, uint64_t, &rex_loan::by_owner > > > rex_net_loan_table
sysio::multi_index< "userres"_n, user_resources > user_resources_table
uint32_t next(octet_iterator &it, octet_iterator end)
#define T(meth, val, expected)
unsigned __int64 uint64_t
Immutable except for fc::from_variant.