-
Notifications
You must be signed in to change notification settings - Fork 15
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #98 from AntelopeIO/eosio.bpay
Tokenomics - eosio.bpay
- Loading branch information
Showing
9 changed files
with
285 additions
and
2 deletions.
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