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

Distribute Asset Market Fees to Referral Program #1419

Merged
merged 17 commits into from
Jan 29, 2019
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
18 changes: 18 additions & 0 deletions libraries/chain/asset_evaluator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,20 @@
#include <locale>

namespace graphene { namespace chain {
namespace detail {
// TODO review and remove code below and links to it after hf_1268
void check_asset_options_hf_1268(const fc::time_point_sec& block_time, const asset_options& options)
{
if( block_time < HARDFORK_1268_TIME )
{
FC_ASSERT( !options.extensions.value.reward_percent.valid(),
"Asset extension reward percent is only available after HARDFORK_1268_TIME!");

FC_ASSERT( !options.extensions.value.whitelist_market_fee_sharing.valid(),
"Asset extension whitelist_market_fee_sharing is only available after HARDFORK_1268_TIME!");
}
}
}

void_result asset_create_evaluator::do_evaluate( const asset_create_operation& op )
{ try {
Expand All @@ -45,6 +59,8 @@ void_result asset_create_evaluator::do_evaluate( const asset_create_operation& o
FC_ASSERT( op.common_options.whitelist_authorities.size() <= chain_parameters.maximum_asset_whitelist_authorities );
FC_ASSERT( op.common_options.blacklist_authorities.size() <= chain_parameters.maximum_asset_whitelist_authorities );

detail::check_asset_options_hf_1268(d.head_block_time(), op.common_options);
OpenLedgerApp marked this conversation as resolved.
Show resolved Hide resolved

// Check that all authorities do exist
for( auto id : op.common_options.whitelist_authorities )
d.get_object(id);
Expand Down Expand Up @@ -277,6 +293,8 @@ void_result asset_update_evaluator::do_evaluate(const asset_update_operation& o)
validate_new_issuer( d, a, *o.new_issuer );
}

detail::check_asset_options_hf_1268(d.head_block_time(), o.new_options);
OpenLedgerApp marked this conversation as resolved.
Show resolved Hide resolved

if( (d.head_block_time() < HARDFORK_572_TIME) || (a.dynamic_asset_data_id(d).current_supply != 0) )
{
// new issuer_permissions must be subset of old issuer permissions
Expand Down
76 changes: 76 additions & 0 deletions libraries/chain/db_balance.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
#include <graphene/chain/asset_object.hpp>
#include <graphene/chain/vesting_balance_object.hpp>
#include <graphene/chain/witness_object.hpp>
#include <boost/range/algorithm.hpp>

namespace graphene { namespace chain {

Expand Down Expand Up @@ -81,9 +82,81 @@ void database::adjust_balance(account_id_type account, asset delta )

} FC_CAPTURE_AND_RETHROW( (account)(delta) ) }

namespace detail {

/**
* Used as a key to search vesting_balance_object in the index
*/
struct vbo_mfs_key
{
account_id_type account_id;
asset_id_type asset_id;

vbo_mfs_key(const account_id_type& account, const asset_id_type& asset):
account_id(account),
asset_id(asset)
{}

bool operator()(const vbo_mfs_key& k, const vesting_balance_object& vbo)const
{
return ( vbo.balance_type == vesting_balance_type::market_fee_sharing ) &&
( k.asset_id == vbo.balance.asset_id ) &&
( k.account_id == vbo.owner );
}

uint64_t operator()(const vbo_mfs_key& k)const
{
return vbo_mfs_hash(k.account_id, k.asset_id);
}
};
} //detail

asset database::get_market_fee_vesting_balance(const account_id_type &account_id, const asset_id_type &asset_id)
{
auto& vesting_balances = get_index_type<vesting_balance_index>().indices().get<by_vesting_type>();
const auto& key = detail::vbo_mfs_key{account_id, asset_id};
auto vbo_it = vesting_balances.find(key, key, key);

if( vbo_it == vesting_balances.end() )
{
return asset(0, asset_id);
}
return vbo_it->balance;
}

void database::deposit_market_fee_vesting_balance(const account_id_type &account_id, const asset &delta)
{ try {
FC_ASSERT( delta.amount >= 0, "Invalid negative value for balance");

if( delta.amount == 0 )
return;

auto& vesting_balances = get_index_type<vesting_balance_index>().indices().get<by_vesting_type>();
const auto& key = detail::vbo_mfs_key{account_id, delta.asset_id};
auto vbo_it = vesting_balances.find(key, key, key);

auto block_time = head_block_time();

if( vbo_it == vesting_balances.end() )
{
create<vesting_balance_object>([&account_id, &delta, &block_time](vesting_balance_object &vbo) {
vbo.owner = account_id;
vbo.balance = delta;
vbo.balance_type = vesting_balance_type::market_fee_sharing;
vbo.policy = instant_vesting_policy{};
});
} else {
modify( *vbo_it, [&block_time, &delta]( vesting_balance_object& vbo )
{
vbo.deposit_vested(block_time, delta);
});
}
} FC_CAPTURE_AND_RETHROW( (account_id)(delta) ) }

optional< vesting_balance_id_type > database::deposit_lazy_vesting(
const optional< vesting_balance_id_type >& ovbid,
share_type amount, uint32_t req_vesting_seconds,
vesting_balance_type balance_type,
account_id_type req_owner,
bool require_vesting )
{
Expand Down Expand Up @@ -117,6 +190,7 @@ optional< vesting_balance_id_type > database::deposit_lazy_vesting(
{
_vbo.owner = req_owner;
_vbo.balance = amount;
_vbo.balance_type = balance_type;

cdd_vesting_policy policy;
policy.vesting_seconds = req_vesting_seconds;
Expand Down Expand Up @@ -152,6 +226,7 @@ void database::deposit_cashback(const account_object& acct, share_type amount, b
acct.cashback_vb,
amount,
get_global_properties().parameters.cashback_vesting_period_seconds,
vesting_balance_type::cashback,
acct.id,
require_vesting );

Expand Down Expand Up @@ -179,6 +254,7 @@ void database::deposit_witness_pay(const witness_object& wit, share_type amount)
wit.pay_vb,
amount,
get_global_properties().parameters.witness_pay_vesting_seconds,
vesting_balance_type::witness,
wit.witness_account,
true );

Expand Down
77 changes: 70 additions & 7 deletions libraries/chain/db_market.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,21 @@
#include <graphene/chain/asset_object.hpp>
#include <graphene/chain/hardfork.hpp>
#include <graphene/chain/market_object.hpp>
#include <graphene/chain/is_authorized_asset.hpp>

#include <fc/uint128.hpp>

namespace graphene { namespace chain {
namespace graphene { namespace chain { namespace detail {

uint64_t calculate_percent(const share_type& value, uint16_t percent)
{
fc::uint128 a(value.value);
a *= percent;
a /= GRAPHENE_100_PERCENT;
return a.to_uint64();
}

} //detail

/**
* All margin positions are force closed at the swan price
Expand Down Expand Up @@ -775,7 +786,10 @@ bool database::fill_limit_order( const limit_order_object& order, const asset& p
const account_object& seller = order.seller(*this);
const asset_object& recv_asset = receives.asset_id(*this);

auto issuer_fees = pay_market_fees( recv_asset, receives );
auto issuer_fees = ( head_block_time() < HARDFORK_1268_TIME ) ?
oxarbitrage marked this conversation as resolved.
Show resolved Hide resolved
pay_market_fees(recv_asset, receives) :
pay_market_fees(seller, recv_asset, receives);

pay_order( seller, receives - issuer_fees, pays );

assert( pays.asset_id != receives.asset_id );
Expand Down Expand Up @@ -1109,10 +1123,8 @@ asset database::calculate_market_fee( const asset_object& trade_asset, const ass
if( trade_asset.options.market_fee_percent == 0 )
return trade_asset.amount(0);

fc::uint128 a(trade_amount.amount.value);
a *= trade_asset.options.market_fee_percent;
a /= GRAPHENE_100_PERCENT;
asset percent_fee = trade_asset.amount(a.to_uint64());
auto value = detail::calculate_percent(trade_amount.amount, trade_asset.options.market_fee_percent);
asset percent_fee = trade_asset.amount(value);

if( percent_fee.amount > trade_asset.options.max_market_fee )
percent_fee.amount = trade_asset.options.max_market_fee;
Expand All @@ -1123,7 +1135,7 @@ asset database::calculate_market_fee( const asset_object& trade_asset, const ass
asset database::pay_market_fees( const asset_object& recv_asset, const asset& receives )
{
auto issuer_fees = calculate_market_fee( recv_asset, receives );
assert(issuer_fees <= receives );
FC_ASSERT( issuer_fees <= receives, "Market fee shouldn't be greater than receives");

//Don't dirty undo state if not actually collecting any fees
if( issuer_fees.amount > 0 )
Expand All @@ -1138,4 +1150,55 @@ asset database::pay_market_fees( const asset_object& recv_asset, const asset& re
return issuer_fees;
}

asset database::pay_market_fees(const account_object& seller, const asset_object& recv_asset, const asset& receives )
{
const auto issuer_fees = calculate_market_fee( recv_asset, receives );
FC_ASSERT( issuer_fees <= receives, "Market fee shouldn't be greater than receives");
//Don't dirty undo state if not actually collecting any fees
if ( issuer_fees.amount > 0 )
{
// calculate and pay rewards
asset reward = recv_asset.amount(0);

auto is_rewards_allowed = [&recv_asset, &seller]() {
const auto &white_list = recv_asset.options.extensions.value.whitelist_market_fee_sharing;
return ( !white_list || (*white_list).empty() || ( (*white_list).find(seller.registrar) != (*white_list).end() ) );
};

if ( is_rewards_allowed() )
{
const auto reward_percent = recv_asset.options.extensions.value.reward_percent;
if ( reward_percent && *reward_percent )
{
const auto reward_value = detail::calculate_percent(issuer_fees.amount, *reward_percent);
if ( reward_value > 0 && is_authorized_asset(*this, seller.registrar(*this), recv_asset) )
{
reward = recv_asset.amount(reward_value);
FC_ASSERT( reward < issuer_fees, "Market reward should be less than issuer fees");
// cut referrer percent from reward
const auto referrer_rewards_percentage = seller.referrer_rewards_percentage;
const auto referrer_rewards_value = detail::calculate_percent(reward.amount, referrer_rewards_percentage);
auto registrar_reward = reward;

if ( referrer_rewards_value > 0 && is_authorized_asset(*this, seller.referrer(*this), recv_asset))
{
FC_ASSERT ( referrer_rewards_value <= reward.amount, "Referrer reward shouldn't be greater than total reward" );
const asset referrer_reward = recv_asset.amount(referrer_rewards_value);
registrar_reward -= referrer_reward;
deposit_market_fee_vesting_balance(seller.referrer, referrer_reward);
}
deposit_market_fee_vesting_balance(seller.registrar, registrar_reward);
}
}
}

const auto& recv_dyn_data = recv_asset.dynamic_asset_data_id(*this);
modify( recv_dyn_data, [&issuer_fees, &reward]( asset_dynamic_data_object& obj ){
obj.accumulated_fees += issuer_fees.amount - reward.amount;
});
}

return issuer_fees;
}

} }
4 changes: 4 additions & 0 deletions libraries/chain/hardfork.d/CORE_1268.hf
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
// #1268 Distribute Asset Market Fees to Referral Program
#ifndef HARDFORK_1268_TIME
#define HARDFORK_1268_TIME (fc::time_point_sec( 1577880000 )) // Wednesday, January 1, 2020 12:00:00 PM
#endif
12 changes: 12 additions & 0 deletions libraries/chain/include/graphene/chain/database.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ namespace graphene { namespace chain {
class transaction_evaluation_state;

struct budget_record;
enum class vesting_balance_type;

/**
* @class database
Expand Down Expand Up @@ -302,6 +303,15 @@ namespace graphene { namespace chain {
*/
void adjust_balance(account_id_type account, asset delta);

void deposit_market_fee_vesting_balance(const account_id_type &account_id, const asset &delta);
/**
* @brief Retrieve a particular account's market fee vesting balance in a given asset
* @param owner Account whose balance should be retrieved
* @param asset_id ID of the asset to get balance in
* @return owner's balance in asset
*/
asset get_market_fee_vesting_balance(const account_id_type &account_id, const asset_id_type &asset_id);

/**
* @brief Helper to make lazy deposit to CDD VBO.
*
Expand All @@ -319,6 +329,7 @@ namespace graphene { namespace chain {
const optional< vesting_balance_id_type >& ovbid,
share_type amount,
uint32_t req_vesting_seconds,
vesting_balance_type balance_type,
account_id_type req_owner,
bool require_vesting );

Expand Down Expand Up @@ -394,6 +405,7 @@ namespace graphene { namespace chain {

asset calculate_market_fee(const asset_object& recv_asset, const asset& trade_amount);
asset pay_market_fees( const asset_object& recv_asset, const asset& receives );
asset pay_market_fees( const account_object& seller, const asset_object& recv_asset, const asset& receives );


///@{
Expand Down
11 changes: 9 additions & 2 deletions libraries/chain/include/graphene/chain/protocol/asset_ops.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,13 @@

namespace graphene { namespace chain {

struct additional_asset_options
{
fc::optional<uint16_t> reward_percent;
fc::optional<flat_set<account_id_type>> whitelist_market_fee_sharing;
};
typedef extension<additional_asset_options> additional_asset_options_t;

bool is_valid_symbol( const string& symbol );

/**
Expand Down Expand Up @@ -75,7 +82,7 @@ namespace graphene { namespace chain {
* size of description.
*/
string description;
extensions_type extensions;
additional_asset_options_t extensions;

/// Perform internal consistency checks.
/// @throws fc::exception if any check fails
Expand Down Expand Up @@ -535,7 +542,7 @@ FC_REFLECT( graphene::chain::bitasset_options,
(extensions)
)


FC_REFLECT( graphene::chain::additional_asset_options, (reward_percent)(whitelist_market_fee_sharing) )
FC_REFLECT( graphene::chain::asset_create_operation::fee_parameters_type, (symbol3)(symbol4)(long_symbol)(price_per_kbyte) )
FC_REFLECT( graphene::chain::asset_global_settle_operation::fee_parameters_type, (fee) )
FC_REFLECT( graphene::chain::asset_settle_operation::fee_parameters_type, (fee) )
Expand Down
10 changes: 9 additions & 1 deletion libraries/chain/include/graphene/chain/protocol/vesting.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,15 @@ namespace graphene { namespace chain {
cdd_vesting_policy_initializer( uint32_t vest_sec = 0, fc::time_point_sec sc = fc::time_point_sec() ):start_claim(sc),vesting_seconds(vest_sec){}
};

typedef fc::static_variant<linear_vesting_policy_initializer, cdd_vesting_policy_initializer> vesting_policy_initializer;
struct instant_vesting_policy_initializer
{
};

typedef fc::static_variant<
linear_vesting_policy_initializer,
cdd_vesting_policy_initializer,
instant_vesting_policy_initializer
> vesting_policy_initializer;


/**
Expand Down Expand Up @@ -117,4 +124,5 @@ FC_REFLECT( graphene::chain::vesting_balance_withdraw_operation, (fee)(vesting_b

FC_REFLECT(graphene::chain::linear_vesting_policy_initializer, (begin_timestamp)(vesting_cliff_seconds)(vesting_duration_seconds) )
FC_REFLECT(graphene::chain::cdd_vesting_policy_initializer, (start_claim)(vesting_seconds) )
FC_REFLECT_EMPTY( graphene::chain::instant_vesting_policy_initializer )
FC_REFLECT_TYPENAME( graphene::chain::vesting_policy_initializer )
Loading