-
Notifications
You must be signed in to change notification settings - Fork 15
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 - eosio.bpay #98
Merged
Merged
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
add_contract(eosio.bpay eosio.bpay ${CMAKE_CURRENT_SOURCE_DIR}/src/eosio.bpay.cpp) | ||
|
||
target_include_directories(eosio.bpay PUBLIC | ||
${CMAKE_CURRENT_SOURCE_DIR}/include | ||
${CMAKE_CURRENT_SOURCE_DIR}/../eosio.system/include | ||
${CMAKE_CURRENT_SOURCE_DIR}/../eosio.token/include) | ||
|
||
set_target_properties(eosio.bpay | ||
PROPERTIES | ||
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}") | ||
|
||
configure_file( ${CMAKE_CURRENT_SOURCE_DIR}/ricardian/eosio.bpay.contracts.md.in ${CMAKE_CURRENT_BINARY_DIR}/ricardian/eosio.bpay.contracts.md @ONLY ) | ||
|
||
target_compile_options( eosio.bpay PUBLIC -R${CMAKE_CURRENT_SOURCE_DIR}/ricardian -R${CMAKE_CURRENT_BINARY_DIR}/ricardian ) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
#pragma once | ||
|
||
#include <eosio/eosio.hpp> | ||
#include <eosio.system/eosio.system.hpp> | ||
#include <eosio.token/eosio.token.hpp> | ||
|
||
using namespace std; | ||
|
||
namespace eosio { | ||
/** | ||
* The `eosio.bpay` contract handles system bpay distribution. | ||
*/ | ||
class [[eosio::contract("eosio.bpay")]] bpay : public contract { | ||
public: | ||
using contract::contract; | ||
|
||
/** | ||
* ## TABLE `rewards` | ||
* | ||
* @param owner - block producer owner account | ||
* @param quantity - reward quantity in EOS | ||
* | ||
* ### example | ||
* | ||
* ```json | ||
* [ | ||
* { | ||
* "owner": "alice", | ||
* "quantity": "8.800 EOS" | ||
* } | ||
* ] | ||
* ``` | ||
*/ | ||
struct [[eosio::table("rewards")]] rewards_row { | ||
name owner; | ||
asset quantity; | ||
|
||
uint64_t primary_key() const { return owner.value; } | ||
}; | ||
typedef eosio::multi_index< "rewards"_n, rewards_row > rewards_table; | ||
|
||
/** | ||
* Claim rewards for a block producer. | ||
* | ||
* @param owner - block producer owner account | ||
*/ | ||
[[eosio::action]] | ||
void claimrewards( const name owner); | ||
|
||
[[eosio::on_notify("eosio.token::transfer")]] | ||
void on_transfer( const name from, const name to, const asset quantity, const string memo ); | ||
|
||
private: | ||
}; | ||
} /// namespace eosio |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
<h1 class="contract">claimrewards</h1> | ||
|
||
--- | ||
spec_version: "0.2.0" | ||
title: Claim Rewards | ||
summary: '{{nowrap owner}} claims block production rewards' | ||
icon: @ICON_BASE_URL@/@MULTISIG_ICON_URI@ | ||
--- | ||
|
||
{{owner}} claims block production rewards accumulated through network fees. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
#include <eosio.bpay/eosio.bpay.hpp> | ||
|
||
namespace eosio { | ||
|
||
void bpay::claimrewards( const name owner ) { | ||
require_auth( owner ); | ||
|
||
rewards_table _rewards( get_self(), get_self().value ); | ||
|
||
const auto& row = _rewards.get( owner.value, "no rewards to claim" ); | ||
|
||
eosio::token::transfer_action transfer( "eosio.token"_n, { get_self(), "active"_n }); | ||
transfer.send( get_self(), owner, row.quantity, "producer block pay" ); | ||
|
||
_rewards.erase(row); | ||
} | ||
|
||
void bpay::on_transfer( const name from, const name to, const asset quantity, const string memo ) { | ||
if (from == get_self() || to != get_self()) { | ||
return; | ||
} | ||
|
||
// ignore eosio system incoming transfers (caused by bpay income transfers eosio => eosio.bpay => producer) | ||
if ( from == "eosio"_n) return; | ||
|
||
symbol system_symbol = eosiosystem::system_contract::get_core_symbol(); | ||
|
||
check( quantity.symbol == system_symbol, "only core token allowed" ); | ||
|
||
rewards_table _rewards( get_self(), get_self().value ); | ||
eosiosystem::producers_table _producers( "eosio"_n, "eosio"_n.value ); | ||
|
||
eosiosystem::global_state_singleton _global("eosio"_n, "eosio"_n.value); | ||
check( _global.exists(), "global state does not exist"); | ||
uint16_t producer_count = _global.get().last_producer_schedule_size; | ||
|
||
asset reward = quantity / producer_count; | ||
|
||
// get producer with the most votes | ||
// using `by_votes` secondary index | ||
auto idx = _producers.get_index<"prototalvote"_n>(); | ||
auto prod = idx.begin(); | ||
|
||
// get top n producers by vote, excluding inactive | ||
std::vector<name> top_producers; | ||
while (true) { | ||
if (prod == idx.end()) break; | ||
if (prod->is_active == false) continue; | ||
|
||
top_producers.push_back(prod->owner); | ||
|
||
if (top_producers.size() == producer_count) break; | ||
|
||
prod++; | ||
} | ||
|
||
// distribute rewards to top producers | ||
for (auto producer : top_producers) { | ||
auto row = _rewards.find( producer.value ); | ||
if (row == _rewards.end()) { | ||
_rewards.emplace( get_self(), [&](auto& row) { | ||
row.owner = producer; | ||
row.quantity = reward; | ||
}); | ||
} else { | ||
_rewards.modify(row, get_self(), [&](auto& row) { | ||
row.quantity += reward; | ||
}); | ||
} | ||
} | ||
} | ||
|
||
} /// namespace eosio |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,101 @@ | ||
#include "eosio.system_tester.hpp" | ||
|
||
using namespace eosio_system; | ||
|
||
BOOST_AUTO_TEST_SUITE(eosio_bpay_tests); | ||
|
||
account_name voter = "alice1111111"_n; | ||
account_name standby = "bp.standby"_n; | ||
account_name inactive = "bp.inactive"_n; | ||
account_name fees = "eosio.fees"_n; | ||
account_name bpay = "eosio.bpay"_n; | ||
|
||
BOOST_FIXTURE_TEST_CASE( bpay_test, eosio_system_tester ) try { | ||
|
||
|
||
// Transferring some tokens to the fees account | ||
// since tokens from eosio will not be directly accepted as contributions to | ||
// the bpay contract | ||
transfer( config::system_account_name, fees, core_sym::from_string("100000.0000"), config::system_account_name ); | ||
|
||
|
||
// Setting up the producers, standby and inactive producers, and voting them in | ||
setup_producer_accounts({standby, inactive}); | ||
auto producer_names = active_and_vote_producers(); | ||
|
||
BOOST_REQUIRE_EQUAL( success(), regproducer(standby) ); | ||
BOOST_REQUIRE_EQUAL( success(), regproducer(inactive) ); | ||
vector<name> top_producers_and_inactive = {inactive}; | ||
top_producers_and_inactive.insert( top_producers_and_inactive.end(), producer_names.begin(), producer_names.begin()+21 ); | ||
|
||
BOOST_REQUIRE_EQUAL( success(), vote( voter, top_producers_and_inactive ) ); | ||
produce_blocks( 250 ); | ||
|
||
|
||
BOOST_REQUIRE_EQUAL( 0, get_producer_info( standby )["unpaid_blocks"].as<uint32_t>() ); | ||
BOOST_REQUIRE_EQUAL( get_producer_info( producer_names[0] )["unpaid_blocks"].as<uint32_t>() > 0, true ); | ||
|
||
// TODO: Check nothing happened here, no rewards since it comes from system account | ||
|
||
asset rewards_sent = core_sym::from_string("1000.0000"); | ||
transfer( fees, bpay, rewards_sent, fees); | ||
|
||
// rewards / 21 | ||
asset balance_per_producer = core_sym::from_string("47.6190"); | ||
|
||
auto rewards = get_bpay_rewards(producer_names[0]); | ||
|
||
// bp.inactive is still active, so should be included in the rewards | ||
BOOST_REQUIRE_EQUAL( get_bpay_rewards(inactive)["quantity"].as<asset>(), balance_per_producer ); | ||
// Random sample | ||
BOOST_REQUIRE_EQUAL( get_bpay_rewards(producer_names[11])["quantity"].as<asset>(), balance_per_producer ); | ||
|
||
|
||
// Deactivating a producer | ||
BOOST_REQUIRE_EQUAL( success(), push_action(config::system_account_name, "rmvproducer"_n, mvo()("producer", inactive) ) ); | ||
BOOST_REQUIRE_EQUAL( false, get_producer_info( inactive )["is_active"].as<bool>() ); | ||
|
||
transfer( fees, bpay, rewards_sent, fees); | ||
BOOST_REQUIRE_EQUAL( get_bpay_rewards(inactive)["quantity"].as<asset>(), balance_per_producer ); | ||
BOOST_REQUIRE_EQUAL( get_bpay_rewards(producer_names[11])["quantity"].as<asset>(), core_sym::from_string("95.2380") ); | ||
|
||
// BP should be able to claim their rewards | ||
{ | ||
auto prod = producer_names[11]; | ||
BOOST_REQUIRE_EQUAL( core_sym::from_string("0.0000"), get_balance( prod ) ); | ||
BOOST_REQUIRE_EQUAL( success(), bpay_claimrewards( prod ) ); | ||
BOOST_REQUIRE_EQUAL( core_sym::from_string("95.2380"), get_balance( prod ) ); | ||
BOOST_REQUIRE_EQUAL( true, get_bpay_rewards(prod).is_null() ); | ||
|
||
// should still have rewards for another producer | ||
BOOST_REQUIRE_EQUAL( get_bpay_rewards(producer_names[10])["quantity"].as<asset>(), core_sym::from_string("95.2380") ); | ||
} | ||
|
||
// Should be able to claim rewards from a producer that is no longer active | ||
{ | ||
BOOST_REQUIRE_EQUAL( core_sym::from_string("0.0000"), get_balance( inactive ) ); | ||
BOOST_REQUIRE_EQUAL( success(), bpay_claimrewards( inactive ) ); | ||
BOOST_REQUIRE_EQUAL( core_sym::from_string("47.6190"), get_balance( inactive ) ); | ||
BOOST_REQUIRE_EQUAL( true, get_bpay_rewards(inactive).is_null() ); | ||
} | ||
|
||
// Should not have rewards for a producer that was never active | ||
{ | ||
BOOST_REQUIRE_EQUAL( true, get_bpay_rewards(standby).is_null() ); | ||
BOOST_REQUIRE_EQUAL( core_sym::from_string("0.0000"), get_balance( standby ) ); | ||
BOOST_REQUIRE_EQUAL( wasm_assert_msg("no rewards to claim"), bpay_claimrewards( standby ) ); | ||
BOOST_REQUIRE_EQUAL( core_sym::from_string("0.0000"), get_balance( standby ) ); | ||
} | ||
|
||
// Tokens transferred from the eosio account should be ignored | ||
{ | ||
transfer( config::system_account_name, bpay, rewards_sent, config::system_account_name ); | ||
BOOST_REQUIRE_EQUAL( get_bpay_rewards(producer_names[10])["quantity"].as<asset>(), core_sym::from_string("95.2380") ); | ||
} | ||
|
||
|
||
|
||
} FC_LOG_AND_RETHROW() | ||
|
||
|
||
BOOST_AUTO_TEST_SUITE_END() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,4 @@ | ||
#include <boost/test/unit_test.hpp> | ||
|
||
#include "eosio.system_tester.hpp" | ||
|
||
using namespace eosio_system; | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this is handy, makes it more flexible 👍
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, I'm not sure what savanna might do to prod count, so...