Skip to content

Commit

Permalink
Merge pull request #145 from GolosChain/75-cyber_stake-improvements
Browse files Browse the repository at this point in the history
cyber.stake improvements #75
  • Loading branch information
afalaleev authored Apr 27, 2019
2 parents abfb3f8 + ddb61bb commit b03abce
Show file tree
Hide file tree
Showing 6 changed files with 158 additions and 119 deletions.
13 changes: 12 additions & 1 deletion cyber.stake/abi/cyber.stake.abi
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,18 @@
"fields": [
{ "type": "symbol", "name": "token_symbol" },
{ "type": "uint8[]", "name": "max_proxies" },
{ "type": "int64", "name": "frame_length" },
{ "type": "int64", "name": "payout_step_length" },
{ "type": "uint16", "name": "payout_steps_num" },
{ "type": "int64", "name": "min_own_staked_for_election" }
]
},{
"name": "open_args",
"base": "",
"fields": [
{ "type": "name", "name": "owner" },
{ "type": "symbol_code", "name": "token_code" },
{ "type": "name?", "name": "ram_payer" }
]
},{
"name": "enable_args",
"base": "",
Expand Down Expand Up @@ -108,6 +115,10 @@
"name": "create",
"type": "create_args",
"ricardian_contract": ""
},{
"name": "open",
"type": "open_args",
"ricardian_contract": ""
},{
"name": "enable",
"type": "enable_args",
Expand Down
23 changes: 17 additions & 6 deletions cyber.stake/include/cyber.stake/cyber.stake.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,6 @@ struct structures {
uint64_t id;
symbol token_symbol;
std::vector<uint8_t> max_proxies;
int64_t frame_length;
int64_t payout_step_length;
uint16_t payout_steps_num;
int64_t min_own_staked_for_election = 0;
Expand All @@ -100,6 +99,7 @@ struct structures {
uint64_t id;
symbol_code token_code;
int64_t total_staked;
time_point_sec last_reward;
bool enabled = false;
uint64_t primary_key()const { return id; }
};
Expand Down Expand Up @@ -127,7 +127,7 @@ struct structures {
using payouts = eosio::multi_index<"payout"_n, structures::payout, payout_id_index, payout_acc_index>;

void update_stake_proxied(symbol_code token_code, name agent_name) {
::update_stake_proxied(token_code.raw(), agent_name.value, int64_t(1), static_cast<int>(true));
::update_stake_proxied(token_code.raw(), agent_name.value, static_cast<int>(true));
}

void send_scheduled_payout(payouts& payouts_table, name account, int64_t payout_step_length, symbol sym, bool claim_mode = false);
Expand All @@ -136,12 +136,12 @@ struct structures {
//return: share
int64_t delegate_traversal(symbol_code token_code, agents_idx_t& agents_idx, grants_idx_t& grants_idx, name agent_name, int64_t amount, bool refill = false);

agents_idx_t::const_iterator get_agent_itr(symbol_code token_code, agents_idx_t& agents_idx, name agent_name, int16_t proxy_level_for_emplaced = -1, agents* agents_table = nullptr, bool* emplaced = nullptr);
agents_idx_t::const_iterator get_agent_itr(symbol_code token_code, agents_idx_t& agents_idx, name agent_name);
void emplace_agent(name account, agents& agents_table, const structures::param& param, name ram_payer);
void add_proxy(symbol_code token_code, grants& grants_table, const structures::agent& grantor_as_agent, const structures::agent& agent,
int16_t pct, int64_t share, int16_t break_fee = -1, int64_t break_min_own_staked = -1);

void change_balance(name account, asset quantity);
void update_stats(const structures::stat& stat_arg, name payer = name());

static inline void staking_exists(symbol_code token_code) {
params params_table(table_owner, table_owner.value);
Expand All @@ -156,6 +156,15 @@ struct structures {
auto agent = get_agent_itr(token_code, agents_idx, account);
agents_idx.modify(agent, name(), f);
}

template<typename Lambda>
void modify_stat(symbol_code token_code, Lambda f) {
stats stats_table(table_owner, table_owner.value);
auto stat = stats_table.find(token_code.raw());
eosio_assert(stat != stats_table.end(), "stat doesn't exist");
stats_table.modify(stat, name(), f);
}

static void check_grant_terms(const structures::agent& agent, int16_t break_fee, int64_t break_min_own_staked);

public:
Expand Down Expand Up @@ -200,16 +209,18 @@ struct structures {
using contract::contract;

[[eosio::action]] void create(symbol token_symbol, std::vector<uint8_t> max_proxies,
int64_t frame_length, int64_t payout_step_length, uint16_t payout_steps_num,
int64_t payout_step_length, uint16_t payout_steps_num,
int64_t min_own_staked_for_election);

[[eosio::action]] void enable(symbol token_symbol);

[[eosio::action]] void open(name owner, symbol_code token_code, std::optional<name> ram_payer);

[[eosio::action]] void delegate(name grantor_name, name agent_name, asset quantity);

[[eosio::action]] void setgrntterms(name grantor_name, name agent_name, symbol_code token_code,
int16_t pct, int16_t break_fee, int64_t break_min_own_staked);
[[eosio::action]] void recall (name grantor_name, name agent_name, symbol_code token_code, int16_t pct);
[[eosio::action]] void recall(name grantor_name, name agent_name, symbol_code token_code, int16_t pct);

[[eosio::action]] void withdraw(name account, asset quantity);
[[eosio::action]] void claim(name account, symbol_code token_code);
Expand Down
153 changes: 64 additions & 89 deletions cyber.stake/src/cyber.stake.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,7 @@ void stake::setgrntterms(name grantor_name, name agent_name, symbol_code token_c
eosio_assert(pct_sum <= config::_100percent, "too high pct value\n");
}
if (!agent_found && pct) {
auto grantor_as_agent = get_agent_itr(token_code, agents_idx, grantor_name, param.max_proxies.size(), &agents_table);
auto grantor_as_agent = get_agent_itr(token_code, agents_idx, grantor_name);
eosio_assert(proxies_num < param.max_proxies[grantor_as_agent->proxy_level - 1], "proxy cannot be added");
update_stake_proxied(token_code, agent_name);
auto agent = get_agent_itr(token_code, agents_idx, agent_name);
Expand All @@ -191,20 +191,19 @@ void stake::on_transfer(name from, name to, asset quantity, std::string memo) {

agents agents_table(table_owner, table_owner.value);
auto agents_idx = agents_table.get_index<"bykey"_n>();
auto agent = get_agent_itr(token_code, agents_idx, account, param.max_proxies.size(), &agents_table);

auto agent = agents_idx.find(std::make_tuple(token_code, account));
if (agent == agents_idx.end()) {
emplace_agent(account, agents_table, param, from);
agent = agents_idx.find(std::make_tuple(token_code, account));
}
update_stake_proxied(token_code, account);

grants grants_table(table_owner, table_owner.value);
auto grants_idx = grants_table.get_index<"bykey"_n>();

auto share = delegate_traversal(token_code, agents_idx, grants_idx, account, quantity.amount, true);
agents_idx.modify(agent, name(), [&](auto& a) { a.own_share += share; });
update_stats(structures::stat {
.id = 0,
.token_code = token_code,
.total_staked = quantity.amount
}, from);
modify_stat(token_code, [&](auto& s) { s.total_staked += quantity.amount; });
}

void stake::claim(name account, symbol_code token_code) {
Expand Down Expand Up @@ -301,31 +300,7 @@ void stake::update_payout(name account, asset quantity, bool claim_mode) {
a.shares_sum += shares_diff;
a.own_share += shares_diff;
});

update_stats(structures::stat {
.id = 0,
.token_code = token_code,
.total_staked = balance_diff
});
}

void stake::update_stats(const structures::stat& stat_arg, name payer) {
stats stats_table(table_owner, table_owner.value);
auto stat = stats_table.find(stat_arg.token_code.raw());

if (stat == stats_table.end() && payer != name()) {
eosio_assert(stat_arg.total_staked >= 0, "SYSTEM: incorrect total_staked");
stats_table.emplace(payer, [&](auto& s) { s = stat_arg; s.id = stat_arg.token_code.raw(); });
}
else if (stat != stats_table.end()) {
stats_table.modify(stat, name(), [&](auto& s) {
s.total_staked += stat_arg.total_staked;
s.enabled = s.enabled || stat_arg.enabled;
});
}
else {
eosio_assert(false, "stats doesn't exist");
}
modify_stat(token_code, [&](auto& s) { s.total_staked += balance_diff; });
}

void stake::send_scheduled_payout(payouts& payouts_table, name account, int64_t payout_step_length, symbol sym, bool claim_mode) {
Expand Down Expand Up @@ -399,11 +374,10 @@ void stake::setproxylvl(name account, symbol_code token_code, uint8_t level) {
eosio_assert(level <= param.max_proxies.size(), "level too high");
agents agents_table(table_owner, table_owner.value);
auto agents_idx = agents_table.get_index<"bykey"_n>();
bool emplaced = false;
auto agent = get_agent_itr(token_code, agents_idx, account, level, &agents_table, &emplaced);
auto agent = get_agent_itr(token_code, agents_idx, account);
eosio_assert(level || agent->min_own_staked >= param.min_own_staked_for_election,
"min_own_staked can't be less than min_own_staked_for_election for users with an ultimate level");
eosio_assert(emplaced || (level != agent->proxy_level), "proxy level has not been changed");
eosio_assert(level != agent->proxy_level, "proxy level has not been changed");
grants grants_table(table_owner, table_owner.value);
auto grants_idx = grants_table.get_index<"bykey"_n>();
uint8_t proxies_num = 0;
Expand All @@ -415,85 +389,87 @@ void stake::setproxylvl(name account, symbol_code token_code, uint8_t level) {
eosio_assert(level || !proxies_num, "can't set an ultimate level because the user has a proxy");
eosio_assert(!level || proxies_num <= param.max_proxies[level - 1], "can't set proxy level, user has too many proxies");

if(!emplaced) {
agents_idx.modify(agent, name(), [&](auto& a) {
a.proxy_level = level;
a.votes = level ? -1 : a.balance;
});
}
agents_idx.modify(agent, name(), [&](auto& a) {
a.proxy_level = level;
a.votes = level ? -1 : a.balance;
});
}

void stake::create(symbol token_symbol, std::vector<uint8_t> max_proxies,
int64_t frame_length, int64_t payout_step_length, uint16_t payout_steps_num,
int64_t payout_step_length, uint16_t payout_steps_num,
int64_t min_own_staked_for_election)
{
eosio::print("create stake for ", token_symbol.code(), "\n");
auto token_code = token_symbol.code();
eosio::print("create stake for ", token_code, "\n");
eosio_assert(max_proxies.size(), "no proxy levels are specified");
eosio_assert(max_proxies.size() < std::numeric_limits<uint8_t>::max(), "too many proxy levels");
if (max_proxies.size() > 1)
for (size_t i = 1; i < max_proxies.size(); i++) {
eosio_assert(max_proxies[i - 1] >= max_proxies[i], "incorrect proxy levels");
}
eosio_assert(frame_length > 0, "incorrect frame_length");
eosio_assert(payout_step_length > 0, "incorrect payout_step_length");
eosio_assert(min_own_staked_for_election >= 0, "incorrect min_own_staked_for_election");
auto issuer = eosio::token::get_issuer(config::token_name, token_symbol.code());
auto issuer = eosio::token::get_issuer(config::token_name, token_code);
require_auth(issuer);
params params_table(table_owner, table_owner.value);
eosio_assert(params_table.find(token_symbol.code().raw()) == params_table.end(), "already exists");
eosio_assert(params_table.find(token_code.raw()) == params_table.end(), "already exists");

params_table.emplace(issuer, [&](auto& p) { p = {
.id = token_symbol.code().raw(),
.id = token_code.raw(),
.token_symbol = token_symbol,
.max_proxies = max_proxies,
.frame_length = frame_length,
.payout_step_length = payout_step_length,
.payout_steps_num = payout_steps_num,
.min_own_staked_for_election = min_own_staked_for_election
};});
};});

stats stats_table(table_owner, table_owner.value);
eosio_assert(stats_table.find(token_code.raw()) == stats_table.end(), "SYSTEM: already exists");
stats_table.emplace(issuer, [&](auto& s) { s = {
.id = token_code.raw(),
.token_code = token_code,
.total_staked = 0
};});
}

void stake::enable(symbol token_symbol) {
auto token_code = token_symbol.code();
auto issuer = eosio::token::get_issuer(config::token_name, token_code);
require_auth(issuer);
params params_table(table_owner, table_owner.value);
params_table.get(token_code.raw(), "no staking for token");
update_stats(structures::stat {
.id = 0,
.token_code = token_code,
.total_staked = 0,
.enabled = true
}, issuer);
modify_stat(token_code, [&](auto& s) {
eosio_assert(!s.enabled, "already enabled");
s.enabled = true;
});
}

stake::agents_idx_t::const_iterator stake::get_agent_itr(symbol_code token_code, stake::agents_idx_t& agents_idx, name agent_name, int16_t proxy_level_for_emplaced, agents* agents_table, bool* emplaced) {
auto key = std::make_tuple(token_code, agent_name);
auto agent = agents_idx.find(key);
void stake::open(name owner, symbol_code token_code, std::optional<name> ram_payer = std::nullopt) {

if (emplaced)
*emplaced = false;
auto actual_ram_payer = ram_payer.value_or(owner);
require_auth(actual_ram_payer);

params params_table(table_owner, table_owner.value);
const auto& param = params_table.get(token_code.raw(), "no staking for token");
agents agents_table(table_owner, table_owner.value);
auto agents_idx = agents_table.get_index<"bykey"_n>();
eosio_assert(agents_idx.find(std::make_tuple(token_code, owner)) == agents_idx.end(), "agent already exists");
emplace_agent(owner, agents_table, param, actual_ram_payer);
}

if(proxy_level_for_emplaced < 0) {
eosio_assert(agent != agents_idx.end(), ("agent " + agent_name.to_string() + " doesn't exist").c_str());
}
else if(agent == agents_idx.end()) {
stake::agents_idx_t::const_iterator stake::get_agent_itr(symbol_code token_code, stake::agents_idx_t& agents_idx, name agent_name) {
auto ret = agents_idx.find(std::make_tuple(token_code, agent_name));
eosio_assert(ret != agents_idx.end(), ("agent " + agent_name.to_string() + " doesn't exist").c_str());
return ret;
}

eosio_assert(static_cast<bool>(agents_table), "SYSTEM: agents_table can't be null");
(*agents_table).emplace(agent_name, [&](auto& a) { a = {
.id = agents_table->available_primary_key(),
.token_code = token_code,
.account = agent_name,
.proxy_level = static_cast<uint8_t>(proxy_level_for_emplaced),
.votes = proxy_level_for_emplaced ? -1 : 0,
.last_proxied_update = time_point_sec(::now())
};});

agent = agents_idx.find(key);
if (emplaced)
*emplaced = true;
}
return agent;
void stake::emplace_agent(name account, agents& agents_table, const structures::param& param, name ram_payer) {
agents_table.emplace(ram_payer, [&](auto& a) { a = {
.id = agents_table.available_primary_key(),
.token_code = param.token_symbol.code(),
.account = account,
.proxy_level = static_cast<uint8_t>(param.max_proxies.size()),
.votes = -1,
.last_proxied_update = time_point_sec(::now())
};});
}

void stake::updatefunds(name account, symbol_code token_code) {
Expand Down Expand Up @@ -538,21 +514,20 @@ void stake::reward(name account, asset quantity) {
a.own_share = quantity.amount;
});
}
update_stats(structures::stat {
.id = 0,
.token_code = token_code,
.total_staked = quantity.amount
}, issuer);
modify_stat(token_code, [&](auto& s) {
s.total_staked += quantity.amount;
s.last_reward = time_point_sec(::now());
});

INLINE_ACTION_SENDER(eosio::token, issue)(config::token_name, {issuer, config::reward_name}, {issuer, quantity, ""});
INLINE_ACTION_SENDER(eosio::token, transfer)(config::token_name, {issuer, config::reward_name},
{issuer, _self, quantity, config::reward_memo});
{issuer, _self, quantity, config::reward_memo});
}

} /// namespace cyber

DISPATCH_WITH_TRANSFER(cyber::stake, cyber::config::token_name, on_transfer,
(create)(enable)(delegate)(setgrntterms)(recall)(withdraw)(claim)(cancelwd)
(create)(enable)(open)(delegate)(setgrntterms)(recall)(withdraw)(claim)(cancelwd)
(setproxylvl)(setproxyfee)(setminstaked)(setkey)
(updatefunds)(reward)
)
5 changes: 3 additions & 2 deletions tests/cyber.govern_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ class cyber_govern_tester : public golos_tester {
BOOST_TEST_MESSAGE("--- creating token and stake");
BOOST_CHECK_EQUAL(success(), token.create(_issuer, asset(max_supply_amount, token._symbol)));
BOOST_CHECK_EQUAL(success(), stake.create(_issuer, token._symbol,
std::vector<uint8_t>{30, 10, 3, 1}, cfg::balances_update_window, 7 * 24 * 60 * 60, 52));
std::vector<uint8_t>{30, 10, 3, 1}, 7 * 24 * 60 * 60, 52));

BOOST_TEST_MESSAGE("--- installing governance contract");
install_contract(govern_account_name, contracts::govern_wasm(), contracts::govern_abi());
Expand Down Expand Up @@ -273,9 +273,9 @@ BOOST_FIXTURE_TEST_CASE(set_producers_test, cyber_govern_tester) try {
BOOST_CHECK_EQUAL(govern.get_active_elected_producers(), govern.make_producers_group(crowd_and_bob));

BOOST_CHECK_EQUAL(success(), token.issue(_issuer, _carol, asset(3, token._symbol), ""));
BOOST_CHECK_EQUAL(success(), token.transfer(_carol, stake_account_name, asset(1, token._symbol)));
BOOST_CHECK_EQUAL(success(), stake.setproxylvl(_carol, token._symbol.to_symbol_code(), 1));

BOOST_CHECK_EQUAL(success(), token.transfer(_carol, stake_account_name, asset(1, token._symbol)));
BOOST_CHECK_EQUAL(success(), stake.delegate(_carol, _bob, asset(1, token._symbol)));

govern.wait_schedule_activation();
Expand Down Expand Up @@ -317,6 +317,7 @@ BOOST_FIXTURE_TEST_CASE(set_producers_test, cyber_govern_tester) try {
BOOST_FIXTURE_TEST_CASE(no_key_test, cyber_govern_tester) try {
BOOST_TEST_MESSAGE("no_key_test");
deploy_sys_contracts();
BOOST_CHECK_EQUAL(success(), stake.open(_alice, token._symbol.to_symbol_code()));
BOOST_CHECK_EQUAL(success(), stake.setproxylvl(_alice, token._symbol.to_symbol_code(), 0));
stake.register_candidate(_bob, token._symbol.to_symbol_code());
govern.wait_schedule_activation();
Expand Down
Loading

0 comments on commit b03abce

Please sign in to comment.