Skip to content

Commit

Permalink
Merge pull request #122 from Tonomy-Foundation/development
Browse files Browse the repository at this point in the history
Testnet release: tokenomics change to vesting.tmy
  • Loading branch information
theblockstalk authored Oct 4, 2024
2 parents c1b9cec + e6bba70 commit 4f5e2c4
Show file tree
Hide file tree
Showing 2 changed files with 112 additions and 23 deletions.
45 changes: 36 additions & 9 deletions contracts/vesting.tmy/include/vesting.tmy/vesting.tmy.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,20 +25,33 @@ namespace vestingtoken
microseconds cliff_period;
microseconds start_delay;
microseconds vesting_period;
double tge_unlock;
};

static const std::map<int, vesting_category> vesting_categories = {
{1, {days(6 * 30), days(0 * 30), days(2 * 365)}}, // Seed Private Sale,
{2, {days(6 * 30), days(6 * 30), days(2 * 365)}}, // Strategic Partnerships Private Sale,
{3, {days(0 * 30), days(0 * 30), days(0 * 30)}}, // Public Sale (DO NOT USED YET),
{4, {days(0 * 30), days(1 * 365), days(5 * 365)}}, // Team and Advisors, Ecosystem
{5, {days(0 * 30), days(0 * 30), days(1 * 365)}}, // Legal and Compliance
{6, {days(0 * 30), days(0 * 30), days(2 * 365)}}, // Reserves, Partnerships, Liquidly Allocation
{7, {days(0 * 30), days(0 * 30), days(5 * 365)}}, // Community and Marketing, Platform Dev, Infra Rewards

{999, {eosio::seconds(10), eosio::seconds(10), eosio::seconds(20)}}, // TESTING ONLY
// DEPRECIATED:
{1, {days(6 * 30), days(0 * 30), days(2 * 365), 0.0}}, // Seed Private Sale (DEPRECIATED),
{2, {days(6 * 30), days(6 * 30), days(2 * 365), 0.0}}, // Strategic Partnerships Private Sale (DEPRECIATED),
// Unchanged:
{3, {days(0 * 30), days(0 * 30), days(0 * 30), 0.0}}, // Public Sale (DO NOT USED YET),
{4, {days(0 * 30), days(1 * 365), days(5 * 365), 0.0}}, // Team and Advisors, Ecosystem
{5, {days(0 * 30), days(0 * 30), days(1 * 365), 0.0}}, // Legal and Compliance
{6, {days(0 * 30), days(0 * 30), days(2 * 365), 0.0}}, // Reserves, Partnerships, Liquidly Allocation
{7, {days(0 * 30), days(0 * 30), days(5 * 365), 0.0}}, // Community and Marketing, Platform Dev, Infra Rewards
// New (replacing depreciated):
{8, {days(0 * 30), days(0 * 30), days(2 * 365), 0.05}}, // Seed (Early Bird)
{9, {days(0 * 30), days(0 * 30), days(2 * 365), 0.025}}, // Seed (Last Chance)
{10, {days(0 * 30), days(14), days(0 * 365), 1.0}}, // Public (TGE)
// Public sale has a delay of 14 days to accommodate the "right of withdrawal" under EU's MICA regulations

// TESTING ONLY:
{997, {days(6 * 30), days(0 * 30), days(2 * 365), 0.0}}, // TESTING ONLY
{998, {eosio::seconds(0), eosio::seconds(10), eosio::seconds(20), 0.5}}, // TESTING ONLY
{999, {eosio::seconds(10), eosio::seconds(10), eosio::seconds(20), 0.0}}, // TESTING ONLY
};

static const std::map<int, bool> depreciated_categories = {{1, true}, {2, true}};

class [[eosio::contract("vesting.tmy")]] vestingToken : public eosio::contract
{
public:
Expand Down Expand Up @@ -105,8 +118,22 @@ namespace vestingtoken
*/
[[eosio::action]] void withdraw(eosio::name holder);

/**
* @details Migrates an allocation to a new amount and category
*
* @internal Auth required by the contract
*
* @param sender {name} - The account name of the sender who created the allocation.
* @param holder {name} - The account name of the token holder.
* @param allocation_id {uint64_t} - The ID of the allocation to be migrated.
* @param amount {asset} - The new amount of tokens to be assigned.
* @param category_id {int} - The new vesting category for the assigned tokens.
*/
[[eosio::action]] void migratealloc(eosio::name sender, name holder, uint64_t allocation_id, eosio::asset old_amount, eosio::asset new_amount, int old_category_id, int new_category_id);

using setsettings_action = action_wrapper<"setsettings"_n, &vestingToken::setsettings>;
using assigntokens_action = action_wrapper<"assigntokens"_n, &vestingToken::assigntokens>;
using withdraw_action = action_wrapper<"withdraw"_n, &vestingToken::withdraw>;
using migratealloc_action = action_wrapper<"migratealloc"_n, &vestingToken::migratealloc>;
};
}
90 changes: 76 additions & 14 deletions contracts/vesting.tmy/src/vesting.tmy.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,20 @@

namespace vestingtoken
{
void check_asset(const eosio::asset &asset)
{
auto sym = asset.symbol;
eosio::check(sym.is_valid(), "invalid amount symbol");
eosio::check(sym == vestingToken::system_resource_currency, "Symbol does not match system resource currency");
eosio::check(sym.precision() == vestingToken::system_resource_currency.precision(), "Symbol precision does not match");
eosio::check(asset.amount > 0, "Amount must be greater than 0");
}

void check_category(int category_id)
{
eosio::check(vesting_categories.contains(category_id), "Invalid new vesting category");
eosio::check(!depreciated_categories.contains(category_id), "New category is depreciated");
}

void vestingToken::setsettings(string sales_date_str, string launch_date_str)
{
Expand All @@ -17,15 +31,8 @@ namespace vestingtoken

void vestingToken::assigntokens(eosio::name sender, eosio::name holder, eosio::asset amount, int category_id)
{
// Check if the provided category exists in the map
eosio::check(vesting_categories.contains(category_id), "Invalid vesting category");

// Check the symbol is correct and valid
auto sym = amount.symbol;
eosio::check(sym.is_valid(), "invalid amount symbol");
eosio::check(sym == system_resource_currency, "Symbol does not match system resource currency");
eosio::check(sym.precision() == system_resource_currency.precision(), "Symbol precision does not match");
eosio::check(amount.amount > 0, "Amount must be greater than 0");
check_category(category_id);
check_asset(amount);

// Create a new vesting schedule
vesting_allocations vesting_table(get_self(), holder.value);
Expand Down Expand Up @@ -93,14 +100,14 @@ namespace vestingtoken

vesting_category category = vesting_categories.at(vesting_allocation.vesting_category_type);

time_point vesting_start = launch_date + vesting_allocation.time_since_sale_start + category.start_delay;
time_point cliff_end = vesting_start + category.cliff_period;
time_point vesting_start = launch_date + category.start_delay;
time_point cliff_finished = vesting_start + category.cliff_period;

// Calculate the vesting end time
time_point vesting_end = vesting_start + category.vesting_period;

// Check if vesting period after cliff has started
if (now >= cliff_end)
if (now >= cliff_finished)
{
// Calculate the total claimable amount
int64_t claimable = 0;
Expand All @@ -110,8 +117,14 @@ namespace vestingtoken
}
else
{
// Calculate the percentage of the vesting period that has passed
double vesting_finished = static_cast<double>((now - vesting_start).count()) / category.vesting_period.count();
claimable = vesting_allocation.tokens_allocated.amount * vesting_finished;
// Calculate the claimable amount:
// + tokens allocated * TGE unlock percentage
// + tokens allocated * % of vesting time that has passed * what is left after TGE unlock
claimable = vesting_allocation.tokens_allocated.amount * ((1.0 - category.tge_unlock) * vesting_finished + category.tge_unlock);
// Ensure the claimable amount is not greater than the total allocated amount
claimable = std::min(claimable, vesting_allocation.tokens_allocated.amount);
}

total_claimable += claimable - vesting_allocation.tokens_claimed.amount;
Expand All @@ -123,7 +136,6 @@ namespace vestingtoken
}
}

eosio::print("]");
if (total_claimable > 0)
{
// Transfer the tokens to the holder
Expand All @@ -135,4 +147,54 @@ namespace vestingtoken
.send();
}
}

// Migrates an allocation to a new amount and category
void vestingToken::migratealloc(eosio::name sender, name holder, uint64_t allocation_id, eosio::asset old_amount, eosio::asset new_amount, int old_category_id, int new_category_id)
{
require_auth(get_self());

check_category(new_category_id);
check_asset(new_amount);

// Get the vesting allocations
vesting_allocations vesting_table(get_self(), holder.value);
auto iter = vesting_table.find(allocation_id);
eosio::check(iter != vesting_table.end(), "Allocation not found");

// Checks to verify new allocation is valid
eosio::check(iter->tokens_allocated.amount == old_amount.amount, "Old amount does not match existing allocation");
eosio::check(iter->vesting_category_type == old_category_id, "Old category does not match existing allocation");
eosio::check(iter->tokens_claimed.amount < new_amount.amount, "New amount is less than the amount already claimed");

// Modify the table row data, and update the table
vesting_table.modify(iter, get_self(), [&](auto &row)
{
row.tokens_allocated = new_amount;
row.vesting_category_type = new_category_id; });

// Notify the holder
eosio::require_recipient(holder);

// // Calculate the change in the allocation amount
int64_t amount_change = new_amount.amount - old_amount.amount;

// If new tokens were allocated, then send them to the contract
if (amount_change > 0)
{
eosio::action({sender, "active"_n},
token_contract_name,
"transfer"_n,
std::make_tuple(sender, get_self(), eosio::asset(amount_change, old_amount.symbol), std::string("Re-allocated vested funds")))
.send();
}
// If tokens were removed, send them back to the sender
else if (amount_change < 0)
{
eosio::action({get_self(), "active"_n},
token_contract_name,
"transfer"_n,
std::make_tuple(get_self(), sender, eosio::asset(-amount_change, old_amount.symbol), std::string("Refunded vested funds")))
.send();
}
}
}

0 comments on commit 4f5e2c4

Please sign in to comment.