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

Feature/127 staking leos #128

Open
wants to merge 4 commits into
base: development
Choose a base branch
from
Open
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
44 changes: 44 additions & 0 deletions contracts/tonomy/include/tonomy/tonomy.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,30 @@ namespace tonomysystem
*/
[[eosio::action]] void sellram(eosio::name dao_owner, eosio::name app, eosio::asset quant);

/**
* Stake tokens for 30 days
*
* @param account_name - the account name of the staker
* @param quantity - the amount of tokens to stake
*/
[[eosio::action]] void staketokens(name account_name, asset quantity);

/**
* Request unstaking, starts a 5-day unstaking period
*
* @param account_name - the account name of the staker
* @param allocation_id - the ID of the staking allocation
*/
[[eosio::action]] void requnstake(name account_name, uint64_t allocation_id);

/**
* Finalize the unstaking process after 5 days
*
* @param account_name - the account name of the staker
* @param allocation_id - the ID of the staking allocation
*/
[[eosio::action]] void releasetoken(name account_name, uint64_t allocation_id);

struct [[eosio::table]] account_type_struct
{
name account_name;
Expand Down Expand Up @@ -268,6 +292,23 @@ namespace tonomysystem
// Following line needed to correctly generate ABI. See https://github.com/EOSIO/eosio.cdt/issues/280#issuecomment-439666574
typedef eosio::multi_index<"resconfig"_n, resource_config> resource_config_table_dump;

// Define the structure of a staking allocation
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i would also like us to add another table, a singleton that contains the total amount of tokens are currently staked/unstaking which should be updated when the member functions are called.

struct [[eosio::table]] staking_allocation
{
uint64_t id;
eosio::name account_name; // The account name of the staker.
eosio::asset tokens_staked; //The amount of tokens staked.
eosio::time_point stake_time; //The time when the staking started.
eosio::time_point unstake_time; //The time when the unstaking will occur.
bool unstake_requested; //A flag indicating whether the tokens are currently being unstaked.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would like us to add a int staking_category field here to make this easier to upgrade in the future. this should be set to 1 for now, but can be used later to change users to different staking systems.

uint64_t primary_key() const { return id; }
EOSLIB_SERIALIZE(struct staking_allocation, (id)(account_name)(tokens_staked)(stake_time)(unstake_time)(unstake_requested))
};

// Define the mapping of staking allocations
typedef eosio::multi_index<"stakingalloc"_n, staking_allocation> staking_allocations;


/**
* Returns the account name of the app that corresponds to the origin
*
Expand Down Expand Up @@ -316,5 +357,8 @@ namespace tonomysystem
using setresparams_action = action_wrapper<"setresparams"_n, &tonomy::setresparams>;
using buyram_action = action_wrapper<"buyram"_n, &tonomy::buyram>;
using sellram_action = action_wrapper<"sellram"_n, &tonomy::sellram>;
using staketokens_action = action_wrapper<"staketokens"_n, &tonomy::staketokens>;
using requnstake_action = action_wrapper<"requnstake"_n, &tonomy::requnstake>;
using releasetoken_action = action_wrapper<"releasetoken"_n, &tonomy::releasetoken>;
};
}
59 changes: 59 additions & 0 deletions contracts/tonomy/src/tonomy.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -497,4 +497,63 @@ namespace tonomysystem
.send();
}

void tonomy::staketokens(name account_name, asset quantity) {
require_auth(account_name);
eosio::check(quantity.amount > 0, "Stake quantity must be greater than zero.");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

staking_allocations _staking(get_self(), get_self().value);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

better to use account_name.value for the scope here like we do https://github.com/Tonomy-Foundation/Tonomy-Contracts/blob/master/contracts/vesting.tmy/src/vesting.tmy.cpp#L38 which makes it easier to fetch the users total balance and iterate through all their allocations


_staking.emplace(account_name, [&](auto& row) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

row.id = _staking.available_primary_key();
row.account_name = account_name;
row.tokens_staked = quantity;
row.stake_time = eosio::current_time_point();
row.unstake_time = eosio::time_point_sec(0); // not unstaked yet
row.unstake_requested = false;
});

// Transfer tokens to the contract
eosio::action(
eosio::permission_level{account_name, "active"_n},
token_contract_name,
"transfer"_n,
std::make_tuple(account_name, get_self(), quantity, std::string("stake tokens"))
).send();
}

void tonomy::requnstake(name account_name, uint64_t allocation_id) {
require_auth(account_name);

staking_allocations _staking(get_self(), get_self().value);
auto itr = _staking.find(allocation_id);
check(itr != _staking.end(), "Staking allocation not found");
check(itr->account_name == account_name, "Not authorized to unstake this allocation");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove this check, it wont be needed if we use the account name to scope the table

check(!itr->unstake_requested, "Unstake already requested");

_staking.modify(itr, eosio::same_payer, [&](auto& row) {
row.unstake_requested = true;
row.unstake_time = eosio::current_time_point() + eosio::days(5);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

row.unstake_time = eosio::current_time_point();

move the 5 day logic to the releasetoken() function. this will be more future proof if we decide to change this later

});
}

void tonomy::releasetoken(name account_name, uint64_t allocation_id) {
require_auth(account_name);

staking_allocations _staking(get_self(), get_self().value);
auto itr = _staking.find(allocation_id);
check(itr != _staking.end(), "Staking allocation not found");
check(itr->account_name == account_name, "Not authorized to finalize unstake for this allocation");
check(itr->unstake_requested, "Unstake not requested");
check(eosio::current_time_point() >= itr->unstake_time, "Unstaking period not yet completed");

// Transfer tokens back to the account
eosio::action(
eosio::permission_level{get_self(), "active"_n},
token_contract_name,
"transfer"_n,
std::make_tuple(get_self(), account_name, itr->tokens_staked, std::string("unstake tokens"))
).send();

_staking.erase(itr);
}

}