Skip to content

Commit

Permalink
Merge pull request #357 from hypha-dao/feature/tokenomics
Browse files Browse the repository at this point in the history
Feature/tokenomics
  • Loading branch information
Gerard097 authored Aug 17, 2023
2 parents bc7d639 + a53dbc6 commit 95c74d8
Show file tree
Hide file tree
Showing 10 changed files with 180 additions and 128 deletions.
4 changes: 4 additions & 0 deletions include/common.hpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#pragma once

#include <config/config.hpp>
#include <eosio/symbol.hpp>
#include <eosio/asset.hpp>
#include <eosio/name.hpp>
Expand Down Expand Up @@ -86,6 +87,9 @@ namespace hypha::common
inline constexpr auto URLS_GROUP = "urls";
inline constexpr auto URL = "url";
inline constexpr auto CLAIM_ENABLED = "claim_enabled";
inline constexpr auto VOICE_MULTIPLIER = "voice_token_multiplier";
inline constexpr auto REWARD_MULTIPLIER = "utility_token_multiplier";
inline constexpr auto PEG_MULTIPLIER = "treasury_token_multiplier";
// 365.25 / 7.4
//const float PHASES_PER_YEAR = 49.3581081081;

Expand Down
2 changes: 1 addition & 1 deletion include/dao.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -477,7 +477,7 @@ namespace pricing {

void onRewardTransfer(const name& from, const name& to, const asset& amount);

AssetBatch calculatePendingClaims(uint64_t assignmentID, const AssetBatch& daoTokens);
//AssetBatch calculatePendingClaims(uint64_t assignmentID, const AssetBatch& daoTokens);

AssetBatch calculatePeriodPayout(Period& period,
const AssetBatch& salary,
Expand Down
4 changes: 1 addition & 3 deletions include/proposals/assignment_proposal.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,6 @@ namespace hypha {
{
return true;
}
private:

asset calculateTimeShareUsdPerPeriod(const SalaryConfig& salaryConf);
private:
};
}
2 changes: 2 additions & 0 deletions include/util.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ namespace hypha
double rewardToPegRatio;
double deferredPerc;
double voiceMultipler = 2.0;
double rewardMultipler = 1.0;
double pegMultipler = 1.0;
};

/**
Expand Down
27 changes: 21 additions & 6 deletions src/assignment.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -59,8 +59,15 @@ namespace hypha

eosio::asset Assignment::getRewardSalary()
{
auto rewardToken = m_daoSettings->getSettingOrDefault<eosio::asset>(common::REWARD_TOKEN);

if (!rewardToken.is_valid()) return {};

//It's posible that the assignment was created before the reward token was setup, so let's check for that case
auto cw = getContentWrapper();

if (!cw.exists(DETAILS, common::REWARD_SALARY_PER_PERIOD)) return {};

asset usdPerPeriod = cw
.getOrFail(DETAILS, USD_SALARY_PER_PERIOD)->getAs<eosio::asset>();

Expand All @@ -75,22 +82,30 @@ namespace hypha
auto rewardToPegVal = normalizeToken(m_daoSettings->getOrFail<eosio::asset>(common::REWARD_TO_PEG_RATIO));

auto rewardPerPeriod = usdPerPeriodCommitmentAdjusted * deferred / rewardToPegVal;

auto rewardToken = m_daoSettings->getOrFail<eosio::asset>(common::REWARD_TOKEN);

return denormalizeToken(rewardPerPeriod, rewardToken);
}

eosio::asset Assignment::getVoiceSalary()
{
return getContentWrapper()
.getOrFail(DETAILS, common::VOICE_SALARY_PER_PERIOD)->getAs<eosio::asset>();
return getContentWrapper()
.getOrFail(DETAILS, common::VOICE_SALARY_PER_PERIOD)->getAs<eosio::asset>();
}

eosio::asset Assignment::getPegSalary()
{
return getContentWrapper()
.getOrFail(DETAILS, common::PEG_SALARY_PER_PERIOD)->getAs<eosio::asset>();
//Since this could be optional let's return invalid asset if not found
auto pegToken = m_daoSettings->getSettingOrDefault<eosio::asset>(common::PEG_TOKEN);

if (!pegToken.is_valid()) return {};

//It's posible that the assignment was created before the reward token was setup, so let's check for that case
auto cw = getContentWrapper();

if (!cw.exists(DETAILS, common::PEG_SALARY_PER_PERIOD)) return {};

return getContentWrapper()
.getOrFail(DETAILS, common::PEG_SALARY_PER_PERIOD)->getAs<eosio::asset>();
}

TimeShare Assignment::getInitialTimeShare()
Expand Down
175 changes: 94 additions & 81 deletions src/dao.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -805,8 +805,8 @@ void dao::claimnextper(uint64_t assignment_id)
)

auto daoTokens = AssetBatch{
.reward = daoSettings->getOrFail<asset>(common::REWARD_TOKEN),
.peg = daoSettings->getOrFail<asset>(common::PEG_TOKEN),
.reward = daoSettings->getSettingOrDefault<asset>(common::REWARD_TOKEN),
.peg = daoSettings->getSettingOrDefault<asset>(common::PEG_TOKEN),
.voice = daoSettings->getOrFail<asset>(common::VOICE_TOKEN)
};

Expand Down Expand Up @@ -844,9 +844,6 @@ void dao::claimnextper(uint64_t assignment_id)
}

// EOS_CHECK(deferredSeeds.is_valid(), "fatal error: SEEDS has to be a valid asset");
EOS_CHECK(ab.peg.is_valid(), "fatal error: PEG has to be a valid asset");
EOS_CHECK(ab.voice.is_valid(), "fatal error: VOICE has to be a valid asset");
EOS_CHECK(ab.reward.is_valid(), "fatal error: REWARD has to be a valid asset");

string assignmentNodeLabel = "";
if (auto [idx, assignmentLabel] = assignment.getContentWrapper().get(SYSTEM, NODE_LABEL); assignmentLabel)
Expand All @@ -862,9 +859,18 @@ void dao::claimnextper(uint64_t assignment_id)

string memo = assignmentNodeLabel + ", period: " + periodToClaim.value().getNodeLabel();

makePayment(daoSettings, periodToClaim.value().getID(), assignee, ab.reward, memo, eosio::name{ 0 }, daoTokens);
if (daoTokens.reward.is_valid()) {
EOS_CHECK(ab.reward.is_valid(), "fatal error: REWARD has to be a valid asset");
makePayment(daoSettings, periodToClaim.value().getID(), assignee, ab.reward, memo, eosio::name{ 0 }, daoTokens);
}

if (daoTokens.peg.is_valid()) {
EOS_CHECK(ab.peg.is_valid(), "fatal error: PEG has to be a valid asset");
makePayment(daoSettings, periodToClaim.value().getID(), assignee, ab.peg, memo, eosio::name{ 0 }, daoTokens);
}

EOS_CHECK(ab.voice.is_valid(), "fatal error: VOICE has to be a valid asset");
makePayment(daoSettings, periodToClaim.value().getID(), assignee, ab.voice, memo, eosio::name{ 0 }, daoTokens);
makePayment(daoSettings, periodToClaim.value().getID(), assignee, ab.peg, memo, eosio::name{ 0 }, daoTokens);
}

// void dao::simclaimall(name account, uint64_t dao_id, bool only_ids)
Expand All @@ -873,8 +879,8 @@ void dao::claimnextper(uint64_t assignment_id)

// //We might reuse if called from simclaimall
// auto daoTokens = AssetBatch{
// .reward = daoSettings->getOrFail<asset>(common::REWARD_TOKEN),
// .peg = daoSettings->getOrFail<asset>(common::PEG_TOKEN),
// .reward = daoSettings->getSettingOrDefault<asset>(common::REWARD_TOKEN),
// .peg = daoSettings->getSettingOrDefault<asset>(common::PEG_TOKEN),
// .voice = daoSettings->getOrFail<asset>(common::VOICE_TOKEN)
// };

Expand Down Expand Up @@ -922,8 +928,8 @@ void dao::claimnextper(uint64_t assignment_id)
// false,
// to_str(
// "{\n",
// "\"peg\":\"", total.peg, "\",\n",
// "\"reward\":\"", total.reward, "\",\n",
// "\"peg\":\"", (total.peg.is_valid() ? to_str(total.peg) : std::string("Not peg")), "\",\n",
// "\"reward\":\"", (total.reward.is_valid() ? to_str(total.reward) : std::string("Not reward")), "\",\n",
// "\"voice\":\"", total.voice, "\",\n",
// "\"ids\":", ids,
// "}"
Expand All @@ -938,16 +944,23 @@ void dao::claimnextper(uint64_t assignment_id)

// //We might reuse if called from simclaimall
// auto daoTokens = AssetBatch{
// .reward = daoSettings->getOrFail<asset>(common::REWARD_TOKEN),
// .peg = daoSettings->getOrFail<asset>(common::PEG_TOKEN),
// .reward = daoSettings->getSettingOrDefault<asset>(common::REWARD_TOKEN),
// .peg = daoSettings->getSettingOrDefault<asset>(common::PEG_TOKEN),
// .voice = daoSettings->getOrFail<asset>(common::VOICE_TOKEN)
// };

// auto pay = calculatePendingClaims(assignment_id, daoTokens);

// EOS_CHECK(
// false,
// to_str("{\n\"peg\":\"", pay.peg, "\",\n\"reward\":\"", pay.reward, "\",\n\"voice\":\"", pay.voice, "\"\n}")
// to_str(
// "{\n",
// "\"peg\":\"", (pay.peg.is_valid() ? to_str(pay.peg) : std::string("Not peg")), "\",\n",
// "\"reward\":\"", (pay.reward.is_valid() ? to_str(pay.reward) : std::string("Not reward")), "\",\n",
// "\"voice\":\"", pay.voice, "\",\n",
// "\"ids\":", ids,
// "}"
// )
// )
// }

Expand All @@ -962,9 +975,9 @@ AssetBatch dao::calculatePeriodPayout(Period& period,
int64_t periodEndSec = period.getEndTime().sec_since_epoch();

AssetBatch payout {
.reward = eosio::asset{ 0, daoTokens.reward.symbol },
.peg = eosio::asset{ 0, daoTokens.peg.symbol },
.voice = eosio::asset{ 0, daoTokens.voice.symbol }
.reward = daoTokens.reward.is_valid() ? asset{ 0, daoTokens.reward.symbol } : asset{},
.peg = daoTokens.peg.is_valid() ? asset{ 0, daoTokens.peg.symbol } : asset{},
.voice = asset{ 0, daoTokens.voice.symbol }
};

while (nextTimeShareOpt)
Expand Down Expand Up @@ -1022,68 +1035,68 @@ AssetBatch dao::calculatePeriodPayout(Period& period,

//Accumlate each of the currencies with the time share multiplier

payout.peg += adjustAsset(salary.peg, commitmentMultiplier);
payout.voice += adjustAsset(salary.voice, commitmentMultiplier);
payout.reward += adjustAsset(salary.reward, commitmentMultiplier);
if (daoTokens.peg.is_valid()) payout.peg += adjustAsset(salary.peg, commitmentMultiplier);
if (daoTokens.reward.is_valid()) payout.reward += adjustAsset(salary.reward, commitmentMultiplier);
}

return payout;
}

AssetBatch dao::calculatePendingClaims(uint64_t assignmentID, const AssetBatch& daoTokens)
{
Assignment assignment(this, assignmentID);
// AssetBatch dao::calculatePendingClaims(uint64_t assignmentID, const AssetBatch& daoTokens)
// {
// Assignment assignment(this, assignmentID);

AssetBatch payAmount {
.reward = eosio::asset{ 0, daoTokens.reward.symbol },
.peg = eosio::asset{ 0, daoTokens.peg.symbol },
.voice = eosio::asset{ 0, daoTokens.voice.symbol }
};
// AssetBatch payAmount {
// .reward = eosio::asset{ 0, daoTokens.reward.symbol },
// .peg = eosio::asset{ 0, daoTokens.peg.symbol },
// .voice = eosio::asset{ 0, daoTokens.voice.symbol }
// };

// Ensure that the claimed period is within the approved period count
Period period = assignment.getStartPeriod();
int64_t periodCount = assignment.getPeriodCount();
int64_t counter = 0;
// // Ensure that the claimed period is within the approved period count
// Period period = assignment.getStartPeriod();
// int64_t periodCount = assignment.getPeriodCount();
// int64_t counter = 0;

const asset pegSalary = assignment.getPegSalary();
const asset voiceSalary = assignment.getVoiceSalary();
const asset rewardSalary = assignment.getRewardSalary();
// const asset pegSalary = assignment.getPegSalary();
// const asset voiceSalary = assignment.getVoiceSalary();
// const asset rewardSalary = assignment.getRewardSalary();

AssetBatch salary{
.reward = rewardSalary,
.peg = pegSalary,
.voice = voiceSalary
};
// AssetBatch salary{
// .reward = rewardSalary,
// .peg = pegSalary,
// .voice = voiceSalary
// };

auto currentTime = eosio::current_time_point().sec_since_epoch();
// auto currentTime = eosio::current_time_point().sec_since_epoch();

const int64_t initTimeShare = assignment.getInitialTimeShare()
.getContentWrapper()
.getOrFail(DETAILS, TIME_SHARE)
->getAs<int64_t>();
// const int64_t initTimeShare = assignment.getInitialTimeShare()
// .getContentWrapper()
// .getOrFail(DETAILS, TIME_SHARE)
// ->getAs<int64_t>();

TimeShare current = assignment.getCurrentTimeShare();
// TimeShare current = assignment.getCurrentTimeShare();

//Initialize nextOpt with current in order to have a valid initial timeShare
auto nextOpt = std::optional<TimeShare>{ current };
// //Initialize nextOpt with current in order to have a valid initial timeShare
// auto nextOpt = std::optional<TimeShare>{ current };

std::optional<TimeShare> lastTimeShare;
// std::optional<TimeShare> lastTimeShare;

while (counter < periodCount)
{
int64_t periodEndSec = period.getEndTime().sec_since_epoch();
if (periodEndSec <= currentTime && // if period has lapsed
!assignment.isClaimed(&period)) // and not yet claimed
{
payAmount += calculatePeriodPayout(period, salary, daoTokens, nextOpt, lastTimeShare, initTimeShare);
nextOpt = lastTimeShare;
}
period = period.next();
counter++;
}
// while (counter < periodCount)
// {
// int64_t periodEndSec = period.getEndTime().sec_since_epoch();
// if (periodEndSec <= currentTime && // if period has lapsed
// !assignment.isClaimed(&period)) // and not yet claimed
// {
// payAmount += calculatePeriodPayout(period, salary, daoTokens, nextOpt, lastTimeShare, initTimeShare);
// nextOpt = lastTimeShare;
// }
// period = period.next();
// counter++;
// }

return payAmount;
}
// return payAmount;
// }

asset dao::getProRatedAsset(ContentWrapper* assignment, const symbol& symbol, const string& key, const float& proration)
{
Expand Down Expand Up @@ -1901,6 +1914,21 @@ void dao::createdao(ContentGroups& config)
#endif
}
else {

//Just do this check on mainnet
if (!isTestnet()) {

auto onboarder = configCW.getOrFail(DETAILS, common::ONBOARDER_ACCOUNT)->getAs<name>();

auto hyphaId = getDAOID("hypha"_n);

EOS_CHECK(
hyphaId.has_value() && Member::isMember(*this, *hyphaId, onboarder),
"You are not allowed to call this action"
);
}

//Regular DAO creation
auto daoDoc = createDao(nullptr);
//Verify Root exists
Document root = Document(get_self(), getRootID());
Expand Down Expand Up @@ -2971,7 +2999,9 @@ void dao::addDefaultSettings(ContentGroup& settingsGroup, const string& daoTitle
sg.push_back({ common::DAO_ORGANISATION_PARAGRAPH, "Select from a multitude of tools to finetune how the organization works. From treasury and compensation to decision-making, from roles to badges, you have every lever at your fingertips." });
sg.push_back({ common::ADD_ADMINS_ENABLED, int64_t(1) });
sg.push_back({ common::CLAIM_ENABLED, int64_t(1) });

sg.push_back({ common::VOICE_MULTIPLIER, int64_t(2) });
sg.push_back({ common::REWARD_MULTIPLIER, int64_t(1) });
sg.push_back({ common::PEG_MULTIPLIER, int64_t(1) });
}

/*
Expand Down Expand Up @@ -3029,24 +3059,6 @@ void dao::readDaoSettings(uint64_t daoID, const name& dao, ContentWrapper config

const name onboarder = onboarderAcc->getAs<name>();

//Just do this check on mainnet
if (!isTestnet()) {

#ifdef EOS_BUILD
EOS_CHECK(
onboarder == eosio::name("dao.hypha"),
"Only authorized account can create DAO"
)
#else
auto hyphaId = getDAOID("hypha"_n);

EOS_CHECK(
hyphaId.has_value() && Member::isMember(*this, *hyphaId, onboarder),
"You are not allowed to call this action"
);
#endif
}

auto votingQuorum = configCW.getOrFail(detailsIdx, VOTING_QUORUM_FACTOR_X100).second;

votingQuorum->getAs<int64_t>();
Expand Down Expand Up @@ -3188,6 +3200,7 @@ void dao::readDaoSettings(uint64_t daoID, const name& dao, ContentWrapper config

//Don't move the token as it it will be used later on
settingsGroup.push_back(*rewardToken);
settingsGroup.push_back(std::move(*rewardToPegTokenRatio));
settingsGroup.push_back(std::move(rewardTokenName));
settingsGroup.push_back(*rewardTokenMaxSupply);
}
Expand Down
Loading

0 comments on commit 95c74d8

Please sign in to comment.