Skip to content

Commit

Permalink
rex2 docs update, ricardians, tests, rename maturity setter
Browse files Browse the repository at this point in the history
  • Loading branch information
Nathan James committed Jun 13, 2024
1 parent 60f3683 commit 2e865e5
Show file tree
Hide file tree
Showing 5 changed files with 70 additions and 30 deletions.
12 changes: 6 additions & 6 deletions contracts/eosio.system/include/eosio.system/eosio.system.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -933,7 +933,7 @@ namespace eosiosystem {
*
* @post User votes are updated following this action.
* @post Tokens used in purchase are added to user's voting power.
* @post Bought REX cannot be sold before 4 days counting from end of day of purchase.
* @post Bought REX cannot be sold before {num_of_maturity_buckets} days counting from end of day of purchase.
*/
[[eosio::action]]
void buyrex( const name& from, const asset& amount );
Expand All @@ -949,7 +949,7 @@ namespace eosiosystem {
*
* @post User votes are updated following this action.
* @post Tokens used in purchase are added to user's voting power.
* @post Bought REX cannot be sold before 4 days counting from end of day of purchase.
* @post Bought REX cannot be sold before {num_of_maturity_buckets} days counting from end of day of purchase.
*/
[[eosio::action]]
void unstaketorex( const name& owner, const name& receiver, const asset& from_net, const asset& from_cpu );
Expand Down Expand Up @@ -1078,7 +1078,7 @@ namespace eosiosystem {
void rexexec( const name& user, uint16_t max );

/**
* Consolidate action, consolidates REX maturity buckets into one bucket that can be sold after 4 days
* Consolidate action, consolidates REX maturity buckets into one bucket that can be sold after {num_of_maturity_buckets} days
* starting from the end of the day.
*
* @param owner - REX owner account name.
Expand All @@ -1090,7 +1090,7 @@ namespace eosiosystem {
* Mvtosavings action, moves a specified amount of REX into savings bucket. REX savings bucket
* never matures. In order for it to be sold, it has to be moved explicitly
* out of that bucket. Then the moved amount will have the regular maturity
* period of 4 days starting from the end of the day.
* period of {num_of_maturity_buckets} days starting from the end of the day.
*
* @param owner - REX owner account name.
* @param rex - amount of REX to be moved.
Expand All @@ -1100,7 +1100,7 @@ namespace eosiosystem {

/**
* Mvfrsavings action, moves a specified amount of REX out of savings bucket. The moved amount
* will have the regular REX maturity period of 4 days.
* will have the regular REX maturity period of {num_of_maturity_buckets} days.
*
* @param owner - REX owner account name.
* @param rex - amount of REX to be moved.
Expand Down Expand Up @@ -1132,7 +1132,7 @@ namespace eosiosystem {
* https://github.com/eosnetworkfoundation/eos-system-contracts/issues/135
*/
[[eosio::action]]
void rexmaturity(const std::optional<uint32_t> num_of_maturity_buckets, const std::optional<bool> sell_matured_rex, const std::optional<bool> buy_rex_to_savings );
void setrexmature(const std::optional<uint32_t> num_of_maturity_buckets, const std::optional<bool> sell_matured_rex, const std::optional<bool> buy_rex_to_savings );

/**
* Donatetorex action, donates funds to REX, increases REX pool return buckets
Expand Down
31 changes: 29 additions & 2 deletions contracts/eosio.system/ricardian/eosio.system.contracts.md.in
Original file line number Diff line number Diff line change
Expand Up @@ -413,6 +413,27 @@ icon: @ICON_BASE_URL@/@REX_ICON_URI@

Performs REX maintenance by processing a maximum of {{max}} REX sell orders and expired loans. Any account can execute this action.

<h1 class="contract">setrexmature</h1>

---
spec_version: "0.2.0"
title: Set REX Maturity Settings
summary: 'Sets the options for REX maturity buckets'
icon: @ICON_BASE_URL@/@REX_ICON_URI@
---

{{#if num_of_maturity_buckets}}
Sets the numbers of maturity buckets to '{{num_of_maturity_buckets}}'
{{/if}}

{{#if sell_matured_rex}}
Sets whether or not to immediately sell matured REX to '{{sell_matured_rex}}'
{{/if}}

{{#if buy_rex_to_savings}}
Sets whether or not to immediately move purchased REX to savings to '{{buy_rex_to_savings}}'
{{/if}}

<h1 class="contract">rmvproducer</h1>

---
Expand Down Expand Up @@ -489,9 +510,15 @@ summary: '{{nowrap from}} sells {{nowrap rex}} tokens'
icon: @ICON_BASE_URL@/@REX_ICON_URI@
---

{{from}} initiates a sell order to sell {{rex}} tokens at the market exchange rate during the time at which the order is ultimately executed. If {{from}} already has an open sell order in the sell queue, {{rex}} will be added to the amount of the sell order without change the position of the sell order within the queue. Once the sell order is executed, proceeds are added to {{from}}’s REX fund, the value of sold REX tokens is deducted from {{from}}’s vote stake, and votes are updated accordingly.
The 'rex' parameter no longer has an effect.

{{from}} initiates a sell order to sell all of their matured REX tokens at the market exchange rate during the time at which the order is ultimately executed.
If {{from}} already has an open sell order in the sell queue, {{rex}} will be added to the amount of the sell order without change the position of the sell order within the queue.
Once the sell order is executed, proceeds are added to {{from}}’s REX fund, the value of sold REX tokens is deducted from {{from}}’s vote stake, and votes are updated accordingly.

Depending on the market conditions, it may not be possible to fill the entire sell order immediately. In such a case, the sell order is added to the back of a sell queue. A sell order at the front of the sell queue will automatically be executed when the market conditions allow for the entire order to be filled. Regardless of the market conditions, the system is designed to execute this sell order within 30 days. {{from}} can cancel the order at any time before it is filled using the cnclrexorder action.
Depending on the market conditions, it may not be possible to fill the entire sell order immediately. In such a case, the sell order is added to the back of a sell queue.
A sell order at the front of the sell queue will automatically be executed when the market conditions allow for the entire order to be filled. Regardless of the market conditions,
the system is designed to execute this sell order within 30 days. {{from}} can cancel the order at any time before it is filled using the cnclrexorder action.

<h1 class="contract">setabi</h1>

Expand Down
4 changes: 2 additions & 2 deletions contracts/eosio.system/src/rex.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ namespace eosiosystem {
using eosio::token;
using eosio::seconds;

void system_contract::rexmaturity(const std::optional<uint32_t> num_of_maturity_buckets, const std::optional<bool> sell_matured_rex, const std::optional<bool> buy_rex_to_savings )
void system_contract::setrexmature(const std::optional<uint32_t> num_of_maturity_buckets, const std::optional<bool> sell_matured_rex, const std::optional<bool> buy_rex_to_savings )
{
require_auth(get_self());

Expand Down Expand Up @@ -945,7 +945,7 @@ namespace eosiosystem {
}

/**
* @brief Calculates maturity time of purchased REX tokens which is 4 days from end
* @brief Calculates maturity time of purchased REX tokens which is {num_of_maturity_buckets} days from end
* of the day UTC
*
* @return time_point_sec
Expand Down
42 changes: 27 additions & 15 deletions tests/eosio.system_rex_matured_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,13 @@ BOOST_FIXTURE_TEST_CASE( buy_sell_matured_rex, eosio_system_tester ) try {
const int64_t ratio = 10000;
const asset init_rent = core_sym::from_string("20000.0000");
const asset init_balance = core_sym::from_string("1000.0000");
const std::vector<account_name> accounts = { "alice"_n, "bob"_n, "charly"_n, "david"_n };
account_name alice = accounts[0], bob = accounts[1], charly = accounts[2], david = accounts[3];
const std::vector<account_name> accounts = { "alice"_n, "bob"_n, "charly"_n, "david"_n, "mark"_n };
account_name alice = accounts[0], bob = accounts[1], charly = accounts[2], david = accounts[3], mark = accounts[4];
setup_rex_accounts( accounts, init_balance );


// 1. set `num_of_maturity_buckets=21` to test increasing maturity time of buying REX tokens.
BOOST_REQUIRE_EQUAL( success(), rexmaturity( 21, false, false ) );
BOOST_REQUIRE_EQUAL( success(), setrexmature( 21, false, false ) );
BOOST_REQUIRE_EQUAL( asset::from_string("25000.0000 REX"), get_buyrex_result( alice, core_sym::from_string("2.5000") ) );
produce_blocks(2);
produce_block(fc::days(5));
Expand All @@ -42,14 +43,14 @@ BOOST_FIXTURE_TEST_CASE( buy_sell_matured_rex, eosio_system_tester ) try {
BOOST_REQUIRE_EQUAL( core_sym::from_string("970.0000"), get_rex_fund(alice) );
BOOST_REQUIRE_EQUAL( get_rex_balance(alice).get_amount(), ratio * asset::from_string("30.0000 REX").get_amount() );
auto rex_pool = get_rex_pool();
BOOST_REQUIRE_EQUAL( core_sym::from_string("30.0000"), rex_pool["total_lendable"].as<asset>() );
BOOST_REQUIRE_EQUAL( core_sym::from_string("30.0000"), rex_pool["total_unlent"].as<asset>() );
BOOST_REQUIRE_EQUAL( core_sym::from_string("0.0000"), rex_pool["total_lent"].as<asset>() );
BOOST_REQUIRE_EQUAL( init_rent, rex_pool["total_rent"].as<asset>() );
BOOST_REQUIRE_EQUAL( get_rex_balance(alice), rex_pool["total_rex"].as<asset>() );

// 2. set `buy_rex_to_savings=false` to test buying REX without moving it to REX savings
BOOST_REQUIRE_EQUAL( success(), rexmaturity( 21, true, false ) );
BOOST_REQUIRE_EQUAL( core_sym::from_string("30.0000"), rex_pool["total_lendable"].as<asset>() );
BOOST_REQUIRE_EQUAL( core_sym::from_string("30.0000"), rex_pool["total_unlent"].as<asset>() );
BOOST_REQUIRE_EQUAL( core_sym::from_string("0.0000"), rex_pool["total_lent"].as<asset>() );
BOOST_REQUIRE_EQUAL( init_rent, rex_pool["total_rent"].as<asset>() );
BOOST_REQUIRE_EQUAL( get_rex_balance(alice), rex_pool["total_rex"].as<asset>() );

// 2. set `sell_matured_rex=true` and `buy_rex_to_savings=false` to test buying REX without moving it to REX savings
BOOST_REQUIRE_EQUAL( success(), setrexmature( 21, true, false ) );
BOOST_REQUIRE_EQUAL( asset::from_string("25000.0000 REX"), get_buyrex_result( bob, core_sym::from_string("2.5000") ) );
produce_blocks(2);
produce_block(fc::days(5));
Expand All @@ -59,8 +60,8 @@ BOOST_FIXTURE_TEST_CASE( buy_sell_matured_rex, eosio_system_tester ) try {
BOOST_REQUIRE_EQUAL( asset::from_string("10000.0000 REX"), get_buyrex_result( bob, core_sym::from_string("1.0000") ) ); // will also triggers sell matured REX
BOOST_REQUIRE_EQUAL( core_sym::from_string("1.0000"), get_rex_vote_stake( bob ) );

// 3. set `sell_matured_rex=false` to test selling matured REX
BOOST_REQUIRE_EQUAL( success(), rexmaturity( 21, false, true ) );
// 3. set `sell_matured_rex=false` and `buy_rex_to_savings=true` to test selling matured REX
BOOST_REQUIRE_EQUAL( success(), setrexmature( 21, false, true ) );
BOOST_REQUIRE_EQUAL( asset::from_string("25000.0000 REX"), get_buyrex_result( charly, core_sym::from_string("2.5000") ) ); // when buying REX, it will automatically be moved to REX savings
BOOST_REQUIRE_EQUAL( success(), mvfrsavings( charly, asset::from_string("25000.0000 REX") ) ); // move REX from savings to initiate matured REX unstaking process
produce_blocks(2);
Expand All @@ -73,12 +74,21 @@ BOOST_FIXTURE_TEST_CASE( buy_sell_matured_rex, eosio_system_tester ) try {
BOOST_REQUIRE_EQUAL( init_balance, get_rex_fund( charly ) );

// 4. legacy holders with matured REX
BOOST_REQUIRE_EQUAL( success(), rexmaturity( 5, false, false ) );
BOOST_REQUIRE_EQUAL( success(), setrexmature( 5, false, false ) );
BOOST_REQUIRE_EQUAL( asset::from_string("25000.0000 REX"), get_buyrex_result( david, core_sym::from_string("2.5000") ) ); // legacy 5 days maturity
BOOST_REQUIRE_EQUAL( asset::from_string("25000.0000 REX"), get_buyrex_result( mark, core_sym::from_string("2.5000") ) );
produce_blocks(2);
produce_block(fc::days(5));
BOOST_REQUIRE_EQUAL( success(), rexmaturity( 21, true, true ) );
BOOST_REQUIRE_EQUAL( success(), setrexmature( 21, true, true ) );
BOOST_REQUIRE_EQUAL( asset::from_string("10000.0000 REX"), get_buyrex_result( david, core_sym::from_string("1.0000") ) ); // new 21 days maturity & triggers sell matured REX

// 4.1. Test selling less than all their matured rex, and having all of their already matured rex sold regardless
BOOST_REQUIRE_EQUAL( core_sym::from_string("2.5000"), get_sellrex_result( mark, asset::from_string("1.0000 REX") ) );
BOOST_REQUIRE_EQUAL( get_rex_balance_obj( mark )["vote_stake"].as<asset>(), core_sym::from_string("0.0000") );
BOOST_REQUIRE_EQUAL( asset::from_string("10000.0000 REX"), get_buyrex_result( mark, core_sym::from_string("1.0000") ) );
BOOST_REQUIRE_EQUAL( success(), mvfrsavings( mark, asset::from_string("10000.0000 REX") ) );
// BOOST_REQUIRE_EQUAL( get_rex_balance_obj( mark )["rex_maturities"].get_array()[0].as<time_point>(), get_rex_balance_obj( mark )["matured_rex"].as<time_point>() );

BOOST_REQUIRE_EQUAL( success(), mvfrsavings( david, asset::from_string("10000.0000 REX") ) ); // must move REX from savings to initiate matured REX unstaking process
BOOST_REQUIRE_EQUAL( wasm_assert_msg("insufficient available rex"), sellrex( david, asset::from_string("25000.0000 REX") ) ); // already sold when previously buying REX
produce_blocks(2);
Expand All @@ -90,6 +100,8 @@ BOOST_FIXTURE_TEST_CASE( buy_sell_matured_rex, eosio_system_tester ) try {
BOOST_REQUIRE_EQUAL( core_sym::from_string("0.0000"), get_rex_vote_stake( david ) );
BOOST_REQUIRE_EQUAL( init_balance, get_rex_fund( david ) );



} FC_LOG_AND_RETHROW()

BOOST_AUTO_TEST_SUITE_END()
11 changes: 6 additions & 5 deletions tests/eosio.system_tester.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -796,13 +796,14 @@ class eosio_system_tester : public TESTER {

asset get_sellrex_result( const account_name& from, const asset& rex ) {
auto trace = base_tester::push_action( config::system_account_name, "sellrex"_n, from, mvo()("from", from)("rex", rex) );
asset proceeds;
asset proceeds = core_sym::from_string("0.0000");
for ( size_t i = 0; i < trace->action_traces.size(); ++i ) {
if ( trace->action_traces[i].act.name == "sellresult"_n ) {
asset _action_proceeds;
fc::raw::unpack( trace->action_traces[i].act.data.data(),
trace->action_traces[i].act.data.size(),
proceeds );
return proceeds;
_action_proceeds );
proceeds += _action_proceeds;
}
}
return proceeds;
Expand Down Expand Up @@ -930,8 +931,8 @@ class eosio_system_tester : public TESTER {
return push_action( name(owner), "closerex"_n, mvo()("owner", owner) );
}

action_result rexmaturity(const std::optional<uint32_t> num_of_maturity_buckets, const std::optional<bool> sell_matured_rex, const std::optional<bool> buy_rex_to_savings ) {
return push_action( "eosio"_n, "rexmaturity"_n, mvo()("num_of_maturity_buckets", num_of_maturity_buckets)("sell_matured_rex", sell_matured_rex)("buy_rex_to_savings", buy_rex_to_savings) );
action_result setrexmature(const std::optional<uint32_t> num_of_maturity_buckets, const std::optional<bool> sell_matured_rex, const std::optional<bool> buy_rex_to_savings ) {
return push_action( "eosio"_n, "setrexmature"_n, mvo()("num_of_maturity_buckets", num_of_maturity_buckets)("sell_matured_rex", sell_matured_rex)("buy_rex_to_savings", buy_rex_to_savings) );
}

action_result donatetorex( const account_name& payer, const asset& quantity, const std::string& memo ) {
Expand Down

0 comments on commit 2e865e5

Please sign in to comment.