Skip to content
This repository has been archived by the owner on Oct 4, 2019. It is now read-only.

Commit

Permalink
Merge pull request #1316 from GolosChain/1045-delegate-vesting-payout…
Browse files Browse the repository at this point in the history
…-strategy-fix-2

Payout strategy for delegate vesting shares #1045 #1041
  • Loading branch information
afalaleev authored May 31, 2019
2 parents 0d8a522 + eb67c17 commit db45d4e
Show file tree
Hide file tree
Showing 12 changed files with 171 additions and 39 deletions.
2 changes: 1 addition & 1 deletion libraries/chain/database.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2307,7 +2307,7 @@ namespace golos { namespace chain {

const auto& delegator = get_account(dvir.account);
asset delegator_vesting = create_vesting(delegator, asset(delegator_claim, STEEM_SYMBOL));
if (dvir.payout_strategy == to_delegated_vesting) {
if (dvir.payout_strategy == delegator_payout_strategy::to_delegated_vesting) {
auto vdo_itr = vdo_idx.find(std::make_tuple(delegatee.name, dvir.account));
if (vdo_itr != vdo_idx.end()) {
modify(delegator, [&](account_object& a) {
Expand Down
1 change: 1 addition & 0 deletions libraries/chain/hardfork.d/0_21.hf
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#define STEEMIT_HARDFORK_0_21__1008 (STEEMIT_HARDFORK_0_21) // Remove limit on max delegate interest witness prop
#define STEEMIT_HARDFORK_0_21__1009 (STEEMIT_HARDFORK_0_21) // Remove limit on min curation percent witness prop
#define STEEMIT_HARDFORK_0_21__1010 (STEEMIT_HARDFORK_0_21) // Fix post bandwidth
#define STEEMIT_HARDFORK_0_21__1045 (STEEMIT_HARDFORK_0_21) // Two payout strategies for vesting delegations with interest

#ifdef STEEMIT_BUILD_TESTNET
#define STEEMIT_HARDFORK_0_21_TIME 1547787600 // 18 jan 2019 12:00:00 MSK
Expand Down
4 changes: 2 additions & 2 deletions libraries/chain/include/golos/chain/account_object.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -209,7 +209,7 @@ class vesting_delegation_object: public object<vesting_delegation_object_type, v
account_name_type delegatee;
asset vesting_shares;
uint16_t interest_rate = 0;
protocol::delegator_payout_strategy payout_strategy = protocol::to_delegator;
protocol::delegator_payout_strategy payout_strategy = protocol::delegator_payout_strategy::to_delegator;
time_point_sec min_delegation_time;
};

Expand Down Expand Up @@ -540,7 +540,7 @@ CHAINBASE_SET_INDEX_TYPE(golos::chain::account_bandwidth_object, golos::chain::a
FC_REFLECT((golos::chain::account_metadata_object), (id)(account)(json_metadata))
CHAINBASE_SET_INDEX_TYPE(golos::chain::account_metadata_object, golos::chain::account_metadata_index)

FC_REFLECT((golos::chain::vesting_delegation_object), (id)(delegator)(delegatee)(vesting_shares)(interest_rate)(min_delegation_time))
FC_REFLECT((golos::chain::vesting_delegation_object), (id)(delegator)(delegatee)(vesting_shares)(interest_rate)(payout_strategy)(min_delegation_time))
CHAINBASE_SET_INDEX_TYPE(golos::chain::vesting_delegation_object, golos::chain::vesting_delegation_index)

FC_REFLECT((golos::chain::vesting_delegation_expiration_object), (id)(delegator)(vesting_shares)(expiration))
Expand Down
2 changes: 1 addition & 1 deletion libraries/chain/include/golos/chain/comment_object.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ namespace golos {

account_name_type account;
uint16_t interest_rate = 0;
protocol::delegator_payout_strategy payout_strategy = protocol::to_delegator;
protocol::delegator_payout_strategy payout_strategy = protocol::delegator_payout_strategy::to_delegator;
};

/**
Expand Down
109 changes: 83 additions & 26 deletions libraries/chain/steem_evaluator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2456,17 +2456,67 @@ namespace {
*/
}

template <typename CreateVdo, typename ValidateWithVdo, typename Operation>
struct delegate_vesting_shares_with_interest_extension_validator {
delegate_vesting_shares_with_interest_extension_validator(const vesting_delegation_object* vdo, database& db)
: _vdo(vdo), _db(db) {
}

using result_type = void;

const vesting_delegation_object* _vdo;
database& _db;

result_type operator()(const delegate_delegator_payout_strategy& ddps) const {
ASSERT_REQ_HF(STEEMIT_HARDFORK_0_21__1045, "delegate_delegator_payout_strategy");

if (_vdo) {
GOLOS_CHECK_LOGIC(_vdo->payout_strategy == ddps.strategy,
logic_exception::cannot_change_delegator_payout_strategy,
"Cannot change payout strategy of already created delegation");
}
}
};

struct delegate_vesting_shares_with_interest_extension_visitor {
delegate_vesting_shares_with_interest_extension_visitor(const vesting_delegation_object* vdo, database& db)
: _vdo(vdo), _db(db) {
}

using result_type = void;

const vesting_delegation_object* _vdo;
database& _db;

result_type operator()(const delegate_delegator_payout_strategy& ddps) const {
if (!_vdo) {
return;
}

_db.modify(*_vdo, [&](vesting_delegation_object& _vdo) {
_vdo.payout_strategy = ddps.strategy;
});
}
};

template <typename Operation>
void delegate_vesting_shares(
database& _db, const chain_properties& median_props, const Operation& op,
CreateVdo&& create_vdo, ValidateWithVdo&& validate_with_vdo
const delegate_vesting_shares_with_interest_extensions_type* extensions, uint16_t interest_rate
) {
const auto& delegator = _db.get_account(op.delegator);
const auto& delegatee = _db.get_account(op.delegatee);
auto delegation = _db.find<vesting_delegation_object, by_delegation>(std::make_tuple(op.delegator, op.delegatee));

if (delegation) {
validate_with_vdo(*delegation);
GOLOS_CHECK_LOGIC(delegation->interest_rate == interest_rate,
logic_exception::cannot_change_delegator_interest_rate,
"Cannot change interest rate of already created delegation");
}

if (extensions) {
for (auto& e : *extensions) {
e.visit(delegate_vesting_shares_with_interest_extension_validator(delegation, _db));
}
}

const auto v_share_price = _db.get_dynamic_global_properties().get_vesting_share_price();
Expand All @@ -2492,12 +2542,14 @@ void delegate_vesting_shares(
});

if (increasing) {
auto delegated = delegator.delegated_vesting_shares;
GOLOS_CHECK_BALANCE(delegator, AVAILABLE_VESTING, delta);

auto elapsed_seconds = (now - delegator.last_vote_time).to_seconds();
auto regenerated_power = (STEEMIT_100_PERCENT * elapsed_seconds) / STEEMIT_VOTE_REGENERATION_SECONDS;
auto current_power = std::min<int64_t>(delegator.voting_power + regenerated_power, STEEMIT_100_PERCENT);
auto max_allowed = (uint128_t(delegator.vesting_shares.amount) * current_power / STEEMIT_100_PERCENT).to_uint64();

auto delegated = delegator.delegated_vesting_shares;
GOLOS_CHECK_LOGIC(delegated + delta <= asset(max_allowed, VESTS_SYMBOL),
logic_exception::delegation_limited_by_voting_power,
"Account allowed to delegate a maximum of ${v} with current voting power = ${p}",
Expand All @@ -2510,49 +2562,64 @@ void delegate_vesting_shares(
"Account must delegate a minimum of ${v}",
("v",min_delegation)("vesting_shares",op.vesting_shares));
});
_db.create<vesting_delegation_object>([&](vesting_delegation_object& o) {

delegation = &_db.create<vesting_delegation_object>([&](vesting_delegation_object& o) {
o.delegator = op.delegator;
o.delegatee = op.delegatee;
o.vesting_shares = op.vesting_shares;
o.min_delegation_time = now;
create_vdo(o);
o.interest_rate = interest_rate;
});
} else {
_db.modify(*delegation, [&](vesting_delegation_object& o) {
o.vesting_shares = op.vesting_shares;
});
}

_db.modify(delegator, [&](account_object& a) {
a.delegated_vesting_shares += delta;
});
_db.modify(delegatee, [&](account_object& a) {
a.received_vesting_shares += delta;
});
} else {
GOLOS_CHECK_OP_PARAM(op, vesting_shares, {
GOLOS_CHECK_LOGIC(op.vesting_shares.amount == 0 || op.vesting_shares >= min_delegation,
logic_exception::cannot_delegate_below_minimum,
"Delegation must be removed or leave minimum delegation amount of ${v}",
("v",min_delegation)("vesting_shares",op.vesting_shares));
});

_db.create<vesting_delegation_expiration_object>([&](vesting_delegation_expiration_object& o) {
o.delegator = op.delegator;
o.vesting_shares = -delta;
o.expiration = std::max(now + STEEMIT_CASHOUT_WINDOW_SECONDS, delegation->min_delegation_time);
});
}

_db.modify(delegatee, [&](account_object& a) {
a.received_vesting_shares += delta;
});
if (delegation) {
if (op.vesting_shares.amount > 0) {
_db.modify(delegatee, [&](account_object& a) {
a.received_vesting_shares += delta;
});

if (op.vesting_shares.amount == 0) {
_db.remove(*delegation);
} else {
_db.modify(*delegation, [&](vesting_delegation_object& o) {
o.vesting_shares = op.vesting_shares;
});
} else {
_db.remove(*delegation);
}
}

if (extensions) {
for (auto& e : *extensions) {
e.visit(delegate_vesting_shares_with_interest_extension_visitor(delegation, _db));
}
}
}

void delegate_vesting_shares_evaluator::do_apply(const delegate_vesting_shares_operation& op) {
const auto& median_props = _db.get_witness_schedule_object().median_props;

delegate_vesting_shares(_db, median_props, op, [&](auto&){}, [&](auto&){});
delegate_vesting_shares(_db, median_props, op, nullptr, 0);
}

void break_free_referral_evaluator::do_apply(const break_free_referral_operation& op) {
Expand Down Expand Up @@ -2584,17 +2651,7 @@ void delegate_vesting_shares(

GOLOS_CHECK_LIMIT_PARAM(op.interest_rate, median_props.max_delegated_vesting_interest_rate);

delegate_vesting_shares(_db, median_props, op, [&](auto& o) {
o.interest_rate = op.interest_rate;
o.payout_strategy = op.payout_strategy;
}, [&](auto& o) {
GOLOS_CHECK_LOGIC(o.interest_rate == op.interest_rate,
logic_exception::cannot_change_delegator_interest_rate,
"Cannot change interest rate of already created delegation");
GOLOS_CHECK_LOGIC(o.payout_strategy == op.payout_strategy,
logic_exception::cannot_change_delegator_payout_strategy,
"Cannot change payout strategy of already created delegation");
});
delegate_vesting_shares(_db, median_props, op, &op.extensions, op.interest_rate);
}

void reject_vesting_shares_delegation_evaluator::do_apply(const reject_vesting_shares_delegation_operation& op) {
Expand Down
26 changes: 23 additions & 3 deletions libraries/protocol/include/golos/protocol/steem_operations.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -1348,20 +1348,38 @@ namespace golos { namespace protocol {
}
};

enum delegator_payout_strategy {
enum class delegator_payout_strategy {
to_delegator,
to_delegated_vesting,
_size
};

struct delegate_delegator_payout_strategy {
delegate_delegator_payout_strategy() {
}

delegate_delegator_payout_strategy(delegator_payout_strategy strat)
: strategy(strat) {
}

delegator_payout_strategy strategy = delegator_payout_strategy::to_delegator;

void validate() const;
};

using delegate_vesting_shares_with_interest_extension = static_variant<
delegate_delegator_payout_strategy
>;

using delegate_vesting_shares_with_interest_extensions_type = flat_set<delegate_vesting_shares_with_interest_extension>;

class delegate_vesting_shares_with_interest_operation : public base_operation {
public:
account_name_type delegator; ///< The account delegating vesting shares
account_name_type delegatee; ///< The account receiving vesting shares
asset vesting_shares; ///< The amount of vesting shares delegated
uint16_t interest_rate = STEEMIT_DEFAULT_DELEGATED_VESTING_INTEREST_RATE; ///< The interest rate wanted by delegator
delegator_payout_strategy payout_strategy = to_delegator; ///< The strategy of delegator vesting payouts
extensions_type extensions; ///< Extensions. Not currently used.
delegate_vesting_shares_with_interest_extensions_type extensions; ///< Extensions.

void validate() const;
void get_required_active_authorities(flat_set<account_name_type>& a) const {
Expand Down Expand Up @@ -1490,5 +1508,7 @@ FC_REFLECT((golos::protocol::chain_properties_update_operation), (owner)(props))
FC_REFLECT((golos::protocol::break_free_referral_operation), (referral)(extensions));

FC_REFLECT_ENUM(golos::protocol::delegator_payout_strategy, (to_delegator)(to_delegated_vesting)(_size))
FC_REFLECT((golos::protocol::delegate_delegator_payout_strategy), (strategy))
FC_REFLECT_TYPENAME((golos::protocol::delegate_vesting_shares_with_interest_extension));
FC_REFLECT((golos::protocol::delegate_vesting_shares_with_interest_operation), (delegator)(delegatee)(vesting_shares)(interest_rate)(extensions));
FC_REFLECT((golos::protocol::reject_vesting_shares_delegation_operation), (delegator)(delegatee)(extensions));
21 changes: 21 additions & 0 deletions libraries/protocol/steem_operations.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -727,12 +727,33 @@ namespace golos { namespace protocol {
GOLOS_CHECK_PARAM_ACCOUNT(referral);
}

struct delegate_vesting_shares_with_interest_extension_validate_visitor {
delegate_vesting_shares_with_interest_extension_validate_visitor() {
}

using result_type = void;

void operator()(const delegate_delegator_payout_strategy& ddps) const {
ddps.validate();
}
};

void delegate_delegator_payout_strategy::validate() const {
GOLOS_CHECK_PARAM(strategy, {
GOLOS_CHECK_VALUE(strategy < delegator_payout_strategy::_size, "This value is reserved");
});
}

void delegate_vesting_shares_with_interest_operation::validate() const {
GOLOS_CHECK_PARAM_ACCOUNT(delegator);
GOLOS_CHECK_PARAM_ACCOUNT(delegatee);
GOLOS_CHECK_LOGIC(delegator != delegatee, logic_exception::cannot_delegate_to_yourself,
"You cannot delegate GESTS to yourself");
GOLOS_CHECK_PARAM(vesting_shares, GOLOS_CHECK_ASSET_GE0(vesting_shares, GESTS));

for (auto& e : extensions) {
e.visit(delegate_vesting_shares_with_interest_extension_validate_visitor());
}
}

void reject_vesting_shares_delegation_operation::validate() const {
Expand Down
3 changes: 2 additions & 1 deletion libraries/wallet/include/golos/wallet/wallet.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -729,9 +729,10 @@ namespace golos { namespace wallet {
* @param delegatee The name of the account receiving GESTS
* @param vesting_shares The amount of GESTS to delegate
* @param interest_rate The interest rate wanted by delegator
* @param payout_strategy The strategy of payout wanted by delegator
* @param broadcast true if you wish to broadcast the transaction
*/
annotated_signed_transaction delegate_vesting_shares_with_interest(string delegator, string delegatee, asset vesting_shares, uint16_t interest_rate, bool broadcast);
annotated_signed_transaction delegate_vesting_shares_with_interest(string delegator, string delegatee, asset vesting_shares, uint16_t interest_rate, delegator_payout_strategy payout_strategy, bool broadcast);


/**
Expand Down
11 changes: 10 additions & 1 deletion libraries/wallet/wallet.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2154,7 +2154,7 @@ fc::ecc::private_key wallet_api::derive_private_key(const std::string& prefix_st
return my->sign_transaction(tx, broadcast);
}

annotated_signed_transaction wallet_api::delegate_vesting_shares_with_interest(string delegator, string delegatee, asset vesting_shares, uint16_t interest_rate, bool broadcast) {
annotated_signed_transaction wallet_api::delegate_vesting_shares_with_interest(string delegator, string delegatee, asset vesting_shares, uint16_t interest_rate, delegator_payout_strategy payout_strategy, bool broadcast) {
WALLET_CHECK_UNLOCKED();

delegate_vesting_shares_with_interest_operation op;
Expand All @@ -2163,6 +2163,15 @@ fc::ecc::private_key wallet_api::derive_private_key(const std::string& prefix_st
op.vesting_shares = vesting_shares;
op.interest_rate = interest_rate;

auto hf = my->_remote_database_api->get_hardfork_version();
if (hf >= hardfork_version(0, STEEMIT_HARDFORK_0_21)) {
delegate_delegator_payout_strategy ddps;
ddps.strategy = payout_strategy;
op.extensions.insert(ddps);
} else {
FC_ASSERT(payout_strategy == delegator_payout_strategy::to_delegator, "Before HF21 enabled only to_delegator payout strategy");
}

signed_transaction tx;
tx.operations.push_back(op);
tx.validate();
Expand Down
8 changes: 8 additions & 0 deletions plugins/account_history/plugin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -486,6 +486,14 @@ if (options.count(name)) { \
insert_receiver(op.account);
}

void operator()(const delegate_vesting_shares_with_interest_operation& op) {
insert_pair(op.delegator, op.delegatee);
}

void operator()(const reject_vesting_shares_delegation_operation& op) {
insert_pair(op.delegatee, op.delegator);
}

// todo: proposal tx signers are receivers
void operator()(const proposal_create_operation& op) {
insert_dual(op.author);
Expand Down
12 changes: 12 additions & 0 deletions plugins/mongo_db/mongo_db_state.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -486,6 +486,18 @@ namespace mongo_db {
format_value(body, "delegatee", delegation.delegatee);
format_value(body, "vesting_shares", delegation.vesting_shares);
format_value(body, "interest_rate", delegation.interest_rate);

std::string payout_strategy;
switch (delegation.payout_strategy) {
case delegator_payout_strategy::to_delegator:
payout_strategy = "to_delegator";
break;
case delegator_payout_strategy::to_delegated_vesting:
payout_strategy = "to_delegated_vesting";
break;
}
format_value(body, "payout_strategy", payout_strategy);

format_value(body, "min_delegation_time", delegation.min_delegation_time);
format_value(body, "timestamp", state_block.timestamp);

Expand Down
Loading

0 comments on commit db45d4e

Please sign in to comment.