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
Changes from 12 commits
Commits
File filter...
Filter file types
Jump to…
Jump to file or symbol
Failed to load files and symbols.

Always

Just for now

@@ -35,6 +35,19 @@
#include <locale>

namespace graphene { namespace chain {
namespace detail {
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 {
@@ -45,6 +58,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);
This conversation was marked as resolved by OpenLedgerApp

This comment has been minimized.

Copy link
@oxarbitrage

oxarbitrage Dec 19, 2018

Member

This check can be removed safely after HF and also the whole check_asset_options_hf_1268 function after the hardfork time pass. Please add Todo: comments around them so we can remove at any hardfork after HARDFORK_1268_TIME

This comment has been minimized.

Copy link
@OpenLedgerApp

OpenLedgerApp Jan 24, 2019

Author Contributor

Done.


// Check that all authorities do exist
for( auto id : op.common_options.whitelist_authorities )
d.get_object(id);
@@ -277,6 +292,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);
This conversation was marked as resolved by OpenLedgerApp

This comment has been minimized.

Copy link
@oxarbitrage

oxarbitrage Dec 19, 2018

Member

same as above.

This comment has been minimized.

Copy link
@OpenLedgerApp

OpenLedgerApp Jan 24, 2019

Author Contributor

Done.


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
@@ -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 {

@@ -80,9 +81,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 )
{
@@ -116,6 +189,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;
@@ -151,6 +225,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 );

@@ -178,6 +253,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 );

@@ -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
@@ -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 ) ?
This conversation was marked as resolved by oxarbitrage

This comment has been minimized.

Copy link
@oxarbitrage

oxarbitrage Dec 19, 2018

Member

please also add comment here so we can just leave pay_market_fees(seller, recv_asset, receives); after hardfork. thanks.

This comment has been minimized.

Copy link
@oxarbitrage

oxarbitrage Dec 19, 2018

Member

sorry, in this one is not possible to remove it, my mistake, please ignore.

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 );
@@ -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;
@@ -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 )
@@ -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;
}

} }
@@ -0,0 +1,4 @@
// #1268 Distribute Asset Market Fees to Referral Program
#ifndef HARDFORK_1268_TIME
#define HARDFORK_1268_TIME (fc::time_point_sec( 1530705600 )) // Wednesday, July 4, 2018 12:00:00 PM
This conversation was marked as resolved by OpenLedgerApp

This comment has been minimized.

Copy link
@pmconrad

pmconrad Nov 7, 2018

Contributor

Please move this timestamp into the far future.
And add a linefeed to the last line.

This comment has been minimized.

Copy link
@OpenLedgerApp

OpenLedgerApp Nov 9, 2018

Author Contributor

Of course, we will change it during the last iteration. Right now the current value is more suitable for us because our smoke tests cover the market fee sharing logic after HARDFORK_1268_TIME

This comment has been minimized.

Copy link
@OpenLedgerApp

OpenLedgerApp Jan 24, 2019

Author Contributor

Done.

#endif
@@ -121,7 +121,7 @@
#define GRAPHENE_RECENTLY_MISSED_COUNT_INCREMENT 4
#define GRAPHENE_RECENTLY_MISSED_COUNT_DECREMENT 3

#define GRAPHENE_CURRENT_DB_VERSION "BTS2.18"
#define GRAPHENE_CURRENT_DB_VERSION "BTS2.19"

#define GRAPHENE_IRREVERSIBLE_THRESHOLD (70 * GRAPHENE_1_PERCENT)

@@ -47,6 +47,7 @@ namespace graphene { namespace chain {
class transaction_evaluation_state;

struct budget_record;
enum class vesting_balance_type;

/**
* @class database
@@ -303,6 +304,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.
*
@@ -320,6 +330,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 );

@@ -395,6 +406,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 );


///@{
@@ -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 );

/**
@@ -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
@@ -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) )
@@ -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;


/**
@@ -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 )
ProTip! Use n and p to navigate between commits in a pull request.
You can’t perform that action at this time.