Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Tokenomics - Fees upgrade #78

Merged
merged 4 commits into from
May 13, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions contracts/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -51,5 +51,6 @@ add_subdirectory(eosio.msig)
add_subdirectory(eosio.system)
add_subdirectory(eosio.token)
add_subdirectory(eosio.wrap)
add_subdirectory(eosio.fees)

add_subdirectory(test_contracts)
11 changes: 11 additions & 0 deletions contracts/eosio.fees/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
add_contract(eosio.fees eosio.fees ${CMAKE_CURRENT_SOURCE_DIR}/src/eosio.fees.cpp)

target_include_directories(eosio.fees PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}/include
${CMAKE_CURRENT_SOURCE_DIR}/../eosio.system/include)

set_target_properties(eosio.fees
PROPERTIES
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}")

target_compile_options( eosio.fees PUBLIC )
35 changes: 35 additions & 0 deletions contracts/eosio.fees/include/eosio.fees/eosio.fees.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
#pragma once

#include <eosio/asset.hpp>
#include <eosio/eosio.hpp>
#include <eosio.system/eosio.system.hpp>

#include <string>

namespace eosiosystem {
class system_contract;
}

namespace eosio {

using std::string;
/**
* The eosio.fees smart contract facilitates the collection of transaction fees from system accounts and their subsequent distribution to the Resource Exchange (REX) pool.
*
* This contract serves as an essential component for inclusion in system-level unit tests.
*
* A comprehensive implementation of the eosio.fees contract can be accessed at EOS Network Foundation GitHub repository.
* https://github.com/eosnetworkfoundation/eosio.fees
*/
class [[eosio::contract("eosio.fees")]] fees : public contract {
public:
using contract::contract;

[[eosio::on_notify("eosio.token::transfer")]]
void on_transfer( const name from, const name to, const asset quantity, const string memo );

[[eosio::action]]
void noop();
};

}
21 changes: 21 additions & 0 deletions contracts/eosio.fees/src/eosio.fees.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
#include <eosio.fees/eosio.fees.hpp>

namespace eosio {

void fees::on_transfer( const name from, const name to, const asset quantity, const string memo )
{
if ( to != get_self() ) {
return;
}
if (eosiosystem::system_contract::rex_available()) {
eosiosystem::system_contract::donatetorex_action donatetorex( "eosio"_n, { get_self(), "active"_n });
donatetorex.send(get_self(), quantity, memo);
}
}

void fees::noop()
{
require_auth( get_self() );
}

} /// namespace eosio
75 changes: 59 additions & 16 deletions contracts/eosio.system/include/eosio.system/eosio.system.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -562,6 +562,7 @@ namespace eosiosystem {
asset quantity;
int64_t bytes_sold;
int64_t ram_bytes;
asset fee;
};

struct action_return_buyram {
Expand All @@ -570,6 +571,7 @@ namespace eosiosystem {
asset quantity;
int64_t bytes_purchased;
int64_t ram_bytes;
asset fee;
};

struct action_return_ramtransfer {
Expand Down Expand Up @@ -745,6 +747,8 @@ namespace eosiosystem {
static constexpr eosio::name names_account{"eosio.names"_n};
static constexpr eosio::name saving_account{"eosio.saving"_n};
static constexpr eosio::name rex_account{"eosio.rex"_n};
static constexpr eosio::name fees_account{"eosio.fees"_n};
static constexpr eosio::name powerup_account{"eosio.powup"_n};
static constexpr eosio::name reserve_account{"eosio.reserv"_n}; // cspell:disable-line
static constexpr eosio::name null_account{"eosio.null"_n};
static constexpr symbol ramcore_symbol = symbol(symbol_code("RAMCORE"), 4);
Expand All @@ -758,8 +762,21 @@ namespace eosiosystem {
// @param system_account - the system account to get the core symbol for.
static symbol get_core_symbol( name system_account = "eosio"_n ) {
rammarket rm(system_account, system_account.value);
const static auto sym = get_core_symbol( rm );
return sym;
auto itr = rm.find(ramcore_symbol.raw());
check(itr != rm.end(), "system contract must first be initialized");
return itr->quote.balance.symbol;
}

// Returns true/false if the rex system is initialized
static bool rex_system_initialized( name system_account = "eosio"_n ) {
eosiosystem::rex_pool_table _rexpool( system_account, system_account.value );
return _rexpool.begin() != _rexpool.end();
}

// Returns true/false if the rex system is available
static bool rex_available( name system_account = "eosio"_n ) {
eosiosystem::rex_pool_table _rexpool( system_account, system_account.value );
return rex_system_initialized() && _rexpool.begin()->total_rex.amount > 0;
}

// Actions:
Expand Down Expand Up @@ -836,6 +853,16 @@ namespace eosiosystem {
[[eosio::action]]
void activate( const eosio::checksum256& feature_digest );

/**
* Logging for actions resulting in system fees.
*
* @param protocol - name of protocol fees were earned from.
* @param fee - the amount of fees collected by system.
* @param memo - (optional) the memo associated with the action.
*/
[[eosio::action]]
void logsystemfee( const name& protocol, const asset& fee, const std::string& memo );

// functions defined in delegate_bandwidth.cpp

/**
Expand Down Expand Up @@ -1092,6 +1119,17 @@ namespace eosiosystem {
[[eosio::action]]
void closerex( const name& owner );

/**
* Donatetorex action, donates funds to REX, increases REX pool return buckets
* Executes inline transfer from payer to system contract of tokens will be executed.
*
* @param payer - the payer of donated funds.
* @param quantity - the quantity of tokens to donated to REX with.
* @param memo - the memo string to accompany the transaction.
*/
[[eosio::action]]
void donatetorex( const name& payer, const asset& quantity, const std::string& memo );

/**
* Undelegate bandwidth action, decreases the total tokens delegated by `from` to `receiver` and/or
* frees the memory associated with the delegation if there is nothing
Expand Down Expand Up @@ -1165,9 +1203,10 @@ namespace eosiosystem {
* @param quantity - the quantity of tokens to buy ram with.
* @param bytes - the quantity of ram to buy specified in bytes.
* @param ram_bytes - the ram bytes held by receiver after the action.
* @param fee - the fee to be paid for the ram sold.
*/
[[eosio::action]]
void logbuyram( const name& payer, const name& receiver, const asset& quantity, int64_t bytes, int64_t ram_bytes );
void logbuyram( const name& payer, const name& receiver, const asset& quantity, int64_t bytes, int64_t ram_bytes, const asset& fee );

/**
* Sell ram action, reduces quota by bytes and then performs an inline transfer of tokens
Expand All @@ -1186,9 +1225,10 @@ namespace eosiosystem {
* @param quantity - the quantity of tokens to sell ram with.
* @param bytes - the quantity of ram to sell specified in bytes.
* @param ram_bytes - the ram bytes held by account after the action.
* @param fee - the fee to be paid for the ram sold.
*/
[[eosio::action]]
void logsellram( const name& account, const asset& quantity, int64_t bytes, int64_t ram_bytes );
void logsellram( const name& account, const asset& quantity, int64_t bytes, int64_t ram_bytes, const asset& fee );

/**
* Transfer ram action, reduces sender's quota by bytes and increase receiver's quota by bytes.
Expand All @@ -1211,6 +1251,17 @@ namespace eosiosystem {
[[eosio::action]]
action_return_ramtransfer ramburn( const name& owner, int64_t bytes, const std::string& memo );

/**
* Buy RAM and immediately burn RAM.
* An inline transfer from payer to system contract of tokens will be executed.
*
* @param payer - the payer of buy RAM & burn.
* @param quantity - the quantity of tokens to buy RAM & burn with.
* @param memo - the memo string to accompany the transaction.
*/
[[eosio::action]]
action_return_buyram buyramburn( const name& payer, const asset& quantity, const std::string& memo );

/**
* Logging for ram changes
*
Expand Down Expand Up @@ -1549,6 +1600,7 @@ namespace eosiosystem {
using setacctnet_action = eosio::action_wrapper<"setacctnet"_n, &system_contract::setacctnet>;
using setacctcpu_action = eosio::action_wrapper<"setacctcpu"_n, &system_contract::setacctcpu>;
using activate_action = eosio::action_wrapper<"activate"_n, &system_contract::activate>;
using logsystemfee_action = eosio::action_wrapper<"logsystemfee"_n, &system_contract::logsystemfee>;
using delegatebw_action = eosio::action_wrapper<"delegatebw"_n, &system_contract::delegatebw>;
using deposit_action = eosio::action_wrapper<"deposit"_n, &system_contract::deposit>;
using withdraw_action = eosio::action_wrapper<"withdraw"_n, &system_contract::withdraw>;
Expand All @@ -1569,6 +1621,7 @@ namespace eosiosystem {
using mvfrsavings_action = eosio::action_wrapper<"mvfrsavings"_n, &system_contract::mvfrsavings>;
using consolidate_action = eosio::action_wrapper<"consolidate"_n, &system_contract::consolidate>;
using closerex_action = eosio::action_wrapper<"closerex"_n, &system_contract::closerex>;
using donatetorex_action = eosio::action_wrapper<"donatetorex"_n, &system_contract::donatetorex>;
using undelegatebw_action = eosio::action_wrapper<"undelegatebw"_n, &system_contract::undelegatebw>;
using buyram_action = eosio::action_wrapper<"buyram"_n, &system_contract::buyram>;
using buyrambytes_action = eosio::action_wrapper<"buyrambytes"_n, &system_contract::buyrambytes>;
Expand All @@ -1577,6 +1630,7 @@ namespace eosiosystem {
using logsellram_action = eosio::action_wrapper<"logsellram"_n, &system_contract::logsellram>;
using ramtransfer_action = eosio::action_wrapper<"ramtransfer"_n, &system_contract::ramtransfer>;
using ramburn_action = eosio::action_wrapper<"ramburn"_n, &system_contract::ramburn>;
using buyramburn_action = eosio::action_wrapper<"buyramburn"_n, &system_contract::buyramburn>;
using logramchange_action = eosio::action_wrapper<"logramchange"_n, &system_contract::logramchange>;
using refund_action = eosio::action_wrapper<"refund"_n, &system_contract::refund>;
using regproducer_action = eosio::action_wrapper<"regproducer"_n, &system_contract::regproducer>;
Expand Down Expand Up @@ -1606,19 +1660,12 @@ namespace eosiosystem {
using unvest_action = eosio::action_wrapper<"unvest"_n, &system_contract::unvest>;

private:
// Implementation details:

static symbol get_core_symbol( const rammarket& rm ) {
auto itr = rm.find(ramcore_symbol.raw());
check(itr != rm.end(), "system contract must first be initialized");
return itr->quote.balance.symbol;
}

//defined in eosio.system.cpp
static eosio_global_state get_default_parameters();
static eosio_global_state4 get_default_inflation_parameters();
symbol core_symbol()const;
void update_ram_supply();
void channel_to_system_fees( const name& from, const asset& amount );
bool execute_next_schedule();

// defined in rex.cpp
Expand All @@ -1629,8 +1676,6 @@ namespace eosiosystem {
const char* error_msg = "must vote for at least 21 producers or for a proxy before buying REX" )const;
rex_order_outcome fill_rex_order( const rex_balance_table::const_iterator& bitr, const asset& rex );
asset update_rex_account( const name& owner, const asset& proceeds, const asset& unstake_quant, bool force_vote_update = false );
void channel_to_rex( const name& from, const asset& amount, bool required = false );
void channel_namebid_to_rex( const int64_t highest_bid );
template <typename T>
int64_t rent_rex( T& table, const name& from, const name& receiver, const asset& loan_payment, const asset& loan_fund );
template <typename T>
Expand All @@ -1640,8 +1685,6 @@ namespace eosiosystem {
void transfer_from_fund( const name& owner, const asset& amount );
void transfer_to_fund( const name& owner, const asset& amount );
bool rex_loans_available()const;
bool rex_system_initialized()const { return _rexpool.begin() != _rexpool.end(); }
bool rex_available()const { return rex_system_initialized() && _rexpool.begin()->total_rex.amount > 0; }
static time_point_sec get_rex_maturity();
asset add_to_rex_balance( const name& owner, const asset& payment, const asset& rex_received );
asset add_to_rex_pool( const asset& payment );
Expand Down
15 changes: 15 additions & 0 deletions contracts/eosio.system/ricardian/eosio.system.contracts.md.in
Original file line number Diff line number Diff line change
Expand Up @@ -454,6 +454,21 @@ Burn {{bytes}} bytes of unused RAM from account {{owner}}.
{{memo}}
{{/if}}

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

---
spec_version: "0.2.0"
title: Buy and Burn RAM
summary: 'Buy and immediately Burn {{quantity}} of RAM from {{nowrap payer}}'
icon: @ICON_BASE_URL@/@RESOURCE_ICON_URI@
---

Buy and Burn {{quantity}} of RAM from account {{payer}}.

{{#if memo}}There is a memo attached to the action stating:
{{memo}}
{{/if}}

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

---
Expand Down
42 changes: 31 additions & 11 deletions contracts/eosio.system/src/delegate_bandwidth.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -56,12 +56,12 @@ namespace eosiosystem {
check( quant.symbol == core_symbol(), "must buy ram with core token" );
check( quant.amount > 0, "must purchase a positive amount" );

auto fee = quant;
asset fee = quant;
fee.amount = ( fee.amount + 199 ) / 200; /// .5% fee (round up)
// fee.amount cannot be 0 since that is only possible if quant.amount is 0 which is not allowed by the assert above.
// If quant.amount == 1, then fee.amount == 1,
// otherwise if quant.amount > 1, then 0 < fee.amount < quant.amount.
auto quant_after_fee = quant;
asset quant_after_fee = quant;
quant_after_fee.amount -= fee.amount;
// quant_after_fee.amount should be > 0 if quant.amount > 1.
// If quant.amount == 1, then quant_after_fee.amount == 0 and the next inline transfer will fail causing the buyram action to fail.
Expand All @@ -72,7 +72,7 @@ namespace eosiosystem {
if ( fee.amount > 0 ) {
token::transfer_action transfer_act{ token_account, { {payer, active_permission} } };
transfer_act.send( payer, ramfee_account, fee, "ram fee" );
channel_to_rex( ramfee_account, fee );
channel_to_system_fees( ramfee_account, fee );
}

int64_t bytes_out;
Expand All @@ -91,13 +91,16 @@ namespace eosiosystem {

// logging
system_contract::logbuyram_action logbuyram_act{ get_self(), { {get_self(), active_permission} } };
logbuyram_act.send( payer, receiver, quant, bytes_out, ram_bytes );
system_contract::logsystemfee_action logsystemfee_act{ get_self(), { {get_self(), active_permission} } };

logbuyram_act.send( payer, receiver, quant, bytes_out, ram_bytes, fee );
logsystemfee_act.send( ram_account, fee, "buy ram" );

// action return value
return action_return_buyram{ payer, receiver, quant, bytes_out, ram_bytes };
return action_return_buyram{ payer, receiver, quant, bytes_out, ram_bytes, fee };
}

void system_contract::logbuyram( const name& payer, const name& receiver, const asset& quantity, int64_t bytes, int64_t ram_bytes ) {
void system_contract::logbuyram( const name& payer, const name& receiver, const asset& quantity, int64_t bytes, int64_t ram_bytes, const asset& fee ) {
require_auth( get_self() );
require_recipient(payer);
require_recipient(receiver);
Expand Down Expand Up @@ -134,23 +137,26 @@ namespace eosiosystem {
token::transfer_action transfer_act{ token_account, { {ram_account, active_permission}, {account, active_permission} } };
transfer_act.send( ram_account, account, asset(tokens_out), "sell ram" );
}
auto fee = ( tokens_out.amount + 199 ) / 200; /// .5% fee (round up)
const int64_t fee = ( tokens_out.amount + 199 ) / 200; /// .5% fee (round up)
// since tokens_out.amount was asserted to be at least 2 earlier, fee.amount < tokens_out.amount
if ( fee > 0 ) {
token::transfer_action transfer_act{ token_account, { {account, active_permission} } };
transfer_act.send( account, ramfee_account, asset(fee, core_symbol()), "sell ram fee" );
channel_to_rex( ramfee_account, asset(fee, core_symbol() ));
channel_to_system_fees( ramfee_account, asset(fee, core_symbol() ));
}

// logging
system_contract::logsellram_action logsellram_act{ get_self(), { {get_self(), active_permission} } };
logsellram_act.send( account, tokens_out, bytes, ram_bytes );
system_contract::logsystemfee_action logsystemfee_act{ get_self(), { {get_self(), active_permission} } };

logsellram_act.send( account, tokens_out, bytes, ram_bytes, asset(fee, core_symbol() ) );
logsystemfee_act.send( ram_account, asset(fee, core_symbol() ), "sell ram" );

// action return value
return action_return_sellram{ account, tokens_out, bytes, ram_bytes };
return action_return_sellram{ account, tokens_out, bytes, ram_bytes, asset(fee, core_symbol() ) };
}

void system_contract::logsellram( const name& account, const asset& quantity, int64_t bytes, int64_t ram_bytes ) {
void system_contract::logsellram( const name& account, const asset& quantity, int64_t bytes, int64_t ram_bytes, const asset& fee ) {
require_auth( get_self() );
require_recipient(account);
}
Expand Down Expand Up @@ -179,6 +185,20 @@ namespace eosiosystem {
return ramtransfer( owner, null_account, bytes, memo );
}

/**
* This action will buy and then burn the purchased RAM bytes.
*/
action_return_buyram system_contract::buyramburn( const name& payer, const asset& quantity, const std::string& memo ) {
require_auth( payer );
check( quantity.symbol == core_symbol(), "quantity must be core token" );
check( quantity.amount > 0, "quantity must be positive" );

const auto return_buyram = buyram( payer, payer, quantity );
ramburn( payer, return_buyram.bytes_purchased, memo );

return return_buyram;
}

[[eosio::action]]
void system_contract::logramchange( const name& owner, int64_t bytes, int64_t ram_bytes )
{
Expand Down
Loading
Loading