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

Refactor peg token redeemption #367

Open
wants to merge 4 commits into
base: master
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
2 changes: 2 additions & 0 deletions include/common.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,8 @@ namespace hypha::common
inline constexpr auto VOICE_MULTIPLIER = "voice_token_multiplier";
inline constexpr auto REWARD_MULTIPLIER = "utility_token_multiplier";
inline constexpr auto PEG_MULTIPLIER = "treasury_token_multiplier";
inline constexpr auto PEG = "peg";
inline constexpr auto REWARD = "reward";
// 365.25 / 7.4
//const float PHASES_PER_YEAR = 49.3581081081;

Expand Down
11 changes: 9 additions & 2 deletions include/dao.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,13 @@ namespace pricing {
eosio::const_mem_fun<TokenToDao, uint64_t, &TokenToDao::by_id>>>
token_to_dao_table;

using reward_token_to_dao_table = token_to_dao_table;

typedef multi_index<name("pegtkentodao"), TokenToDao,
eosio::indexed_by<name("bydocid"),
eosio::const_mem_fun<TokenToDao, uint64_t, &TokenToDao::by_id>>>
peg_token_to_dao_table;

TABLE NameToID
{
uint64_t id;
Expand Down Expand Up @@ -119,7 +126,7 @@ namespace pricing {
eosio::indexed_by<name("byassignment"), eosio::const_mem_fun<Payment, uint64_t, &Payment::by_assignment>>>
payment_table;

ACTION assigntokdao(asset token, uint64_t dao_id, bool force);
ACTION assigntokdao(asset token, uint64_t dao_id, const string& token_type, bool force);

ACTION propose(uint64_t dao_id, const name &proposer, const name &proposal_type, ContentGroups &content_groups, bool publish);
ACTION vote(const name& voter, uint64_t proposal_id, string &vote, const std::optional<string> & notes);
Expand Down Expand Up @@ -478,7 +485,7 @@ namespace pricing {

void verifyDaoType(uint64_t daoID);

void pushPegTokenSettings(name dao, ContentGroup& settingsGroup, ContentWrapper configCW, int64_t detailsIdx, bool create);
void pushPegTokenSettings(name dao, uint64_t daoID, ContentGroup& settingsGroup, ContentWrapper configCW, int64_t detailsIdx, bool create);
void pushVoiceTokenSettings(name dao, ContentGroup& settingsGroup, ContentWrapper configCW, int64_t detailsIdx, bool create);
void pushRewardTokenSettings(name dao, uint64_t daoID, ContentGroup& settingsGroup, ContentWrapper configCW, int64_t detailsIdx, bool create);

Expand Down
1 change: 0 additions & 1 deletion src/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
project(dao)

set(EOSIO_WASM_OLD_BEHAVIOR "Off")

find_package(eosio.cdt)

# Activate Logging
Expand Down
111 changes: 78 additions & 33 deletions src/dao.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -81,20 +81,35 @@ void dao::cleandao(uint64_t dao_id)

remNameID<dao_table>(name);

token_to_dao_table tok_t(get_self(), get_self().value);
// Clean reward token entry if any
{
token_to_dao_table tok_t(get_self(), get_self().value);

auto by_id = tok_t.get_index<"bydocid"_n>();
auto idIt = by_id.find(dao_id);

if (idIt != by_id.end()){
by_id.erase(idIt);
auto by_id = tok_t.get_index<"bydocid"_n>();
auto idIt = by_id.find(dao_id);

if (idIt != by_id.end()){
by_id.erase(idIt);
}
}

// Clean peg token entry if any
{
peg_token_to_dao_table tok_t(get_self(), get_self().value);

auto by_id = tok_t.get_index<"bydocid"_n>();
auto idIt = by_id.find(dao_id);

if (idIt != by_id.end()){
by_id.erase(idIt);
}
}

auto voiceContract = getSettingOrFail<eosio::name>(GOVERNANCE_TOKEN_CONTRACT);

//delete voice token, reward and peg tokens are not deletable ATM
eosio::action(
eosio::permission_level(get_self(), eosio::name("active")),
eosio::permission_level(voiceContract, eosio::name("active")),
voiceContract,
eosio::name("del"),
std::make_tuple(name, asset{0, symbol{"VOICE", 2}})
Expand Down Expand Up @@ -2269,7 +2284,7 @@ void dao::createtokens(uint64_t dao_id, ContentGroups& tokens_info)
auto daoName = daoSettings->getOrFail<name>(DAO_NAME);

if (auto [pegIdx, pegGroup] = cw.getGroup("peg_details"); pegGroup) {
pushPegTokenSettings(daoName, *settingsGroup, cw, pegIdx, true);
pushPegTokenSettings(daoName, dao_id, *settingsGroup, cw, pegIdx, true);
}

if (auto [rewardIdx, rewardGroup] = cw.getGroup("reward_details"); rewardGroup) {
Expand Down Expand Up @@ -3069,38 +3084,54 @@ void dao::createToken(const std::string& contractType, name issuer, const asset&
).send();
}

void dao::assigntokdao(asset token, uint64_t dao_id, bool force)
void dao::assigntokdao(asset token, uint64_t dao_id, const string& token_type, bool force)
{
eosio::require_auth(get_self());

token_to_dao_table tok_t(get_self(), get_self().value);
auto assignToTable = [&](auto&& table) {

auto it = tok_t.find(token.symbol.raw());
auto insert = [&](TokenToDao& entry){
entry.id = dao_id;
entry.token = token;
};

auto it = table.find(token.symbol.raw());

auto insert = [&](TokenToDao& entry){
entry.id = dao_id;
entry.token = token;
};
{
auto by_id = table.template get_index<"bydocid"_n>();
auto idIt = by_id.find(dao_id);
EOS_CHECK(
force || idIt == by_id.end(),
to_str("There is already an entry for the specified dao_id: ", idIt->token)
);
}

{
auto by_id = tok_t.get_index<"bydocid"_n>();
auto idIt = by_id.find(dao_id);
EOS_CHECK(
force || idIt == by_id.end(),
to_str("There is already an entry for the specified dao_id: ", idIt->token)
);
}
if (it != table.end()) {
EOS_CHECK(
force,
to_str("There is already an entry for the specified asset: ", it->id)
);

if (it != tok_t.end()) {
EOS_CHECK(
force,
to_str("There is already an entry for the specified asset: ", it->id)
);
table.modify(it, eosio::same_payer, insert);
}
else {
table.emplace(get_self(), insert);
}
};

tok_t.modify(it, eosio::same_payer, insert);
if (token_type == common::PEG) {
peg_token_to_dao_table tok_t(get_self(), get_self().value);
assignToTable(tok_t);
}
else if (token_type == common::REWARD) {
reward_token_to_dao_table tok_t(get_self(), get_self().value);
assignToTable(tok_t);
}
else {
tok_t.emplace(get_self(), insert);
EOS_CHECK(
false,
"Invalid token type, expected [peg | reward]"
);
}
}

Expand Down Expand Up @@ -3245,6 +3276,7 @@ void dao::pushRewardTokenSettings(name dao, uint64_t daoID, ContentGroup& settin
std::make_tuple(
rewardToken->getAs<asset>(),
daoID,
std::string(common::REWARD),
false
)
).send();
Expand Down Expand Up @@ -3290,7 +3322,7 @@ void dao::pushVoiceTokenSettings(name dao, ContentGroup& settingsGroup, ContentW
}
}

void dao::pushPegTokenSettings(name dao, ContentGroup& settingsGroup, ContentWrapper configCW, int64_t detailsIdx, bool create) {
void dao::pushPegTokenSettings(name dao, uint64_t daoID, ContentGroup& settingsGroup, ContentWrapper configCW, int64_t detailsIdx, bool create) {

if (settingsGroup.size() == 2) {

Expand Down Expand Up @@ -3339,6 +3371,18 @@ void dao::pushPegTokenSettings(name dao, ContentGroup& settingsGroup, ContentWra

if (create) {

eosio::action(
eosio::permission_level{ get_self(), name("active") },
get_self(),
name("assigntokdao"),
std::make_tuple(
pegToken->getAs<asset>(),
daoID,
std::string(common::PEG),
false
)
).send();

auto dhoSettings = getSettingsDocument();

createToken(
Expand Down Expand Up @@ -3483,7 +3527,7 @@ void dao::readDaoSettings(uint64_t daoID, const name& dao, ContentWrapper config
pushVoiceTokenSettings(dao, settingsGroup, configCW, detailsIdx, !isDraft);

if (!skipPegTok) {
pushPegTokenSettings(dao, settingsGroup, configCW, detailsIdx, !isDraft);
pushPegTokenSettings(dao, daoID, settingsGroup, configCW, detailsIdx, !isDraft);
}

if (!skipRewardTok) {
Expand Down Expand Up @@ -3516,7 +3560,8 @@ void dao::reset() {
delete_table<election_vote_table>(get_self(), 1);
delete_table<election_vote_table>(get_self(), 2);
delete_table<election_vote_table>(get_self(), 3);
delete_table<token_to_dao_table>(get_self(), get_self().value);
delete_table<reward_token_to_dao_table>(get_self(), get_self().value);
delete_table<peg_token_to_dao_table>(get_self(), get_self().value);
delete_table<dao_table>(get_self(), get_self().value);
delete_table<member_table>(get_self(), get_self().value);
delete_table<payment_table>(get_self(), get_self().value);
Expand Down
53 changes: 23 additions & 30 deletions src/treasury/actions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -486,32 +486,19 @@ void dao::onCashTokenTransfer(const name& from, const name& to, const asset& qua
EOS_CHECK(quantity.amount > 0, "quantity must be > 0");
EOS_CHECK(quantity.is_valid(), "quantity invalid");

//Since the symbols must be unique for each Cash token we can use the
//raw value as the edge name
name lookupEdgeName = name(quantity.symbol.raw());

//This would be a very weird scenario where the symbol raw value
//equals the edge name 'dao' which would cause unexpected behaviour
if (lookupEdgeName == common::DAO) {
// auto settings = getSettingsDocument();
// settings->setSetting(
// "errors",
// Content{ "cash_critital_error", to_str("Symbol raw value colapses with 'dao' edge name:", quantity) }
// );
EOS_CHECK(
false,
to_str("Symbol raw value colapses with 'dao' edge name:", quantity)
)
// Find the token by the raw value
auto tokenRaw = quantity.symbol.raw();

return;
}
peg_token_to_dao_table tok_t(get_self(), get_self().value);

auto it = tok_t.find(tokenRaw);

uint64_t daoID = 0;

auto rootID = getRootID();
//Fast lookup
if (auto [exists, edge] = Edge::getIfExists(get_self(), rootID, lookupEdgeName); exists) {
daoID = edge.getToNode();
if (it != tok_t.end()) {
daoID = it->id;
}
//We have to find which DAO this token belongs to (if any)
else {
Expand All @@ -522,25 +509,31 @@ void dao::onCashTokenTransfer(const name& from, const name& to, const asset& qua

//Some DAO's might not have a peg token so let's use the default asset{}
if (daoSettings->getSettingOrDefault<asset>(common::PEG_TOKEN).symbol == quantity.symbol) {
//If we find it, let's create a lookup edge for the next time we get this symbol
//If we find it, let's create a lookup entry for the next time we get this symbol
daoID = edge.getToNode();
Edge(get_self(), get_self(), rootID, daoID, lookupEdgeName);

tok_t.emplace(get_self(), [&](TokenToDao& entry){
entry.id = daoID;
entry.token = asset{1, quantity.symbol};
});

break;
}
}
}

EOS_CHECK(
daoID != 0,
"No DAO uses the transfered token"
);
// This token doesn't belong to any DAO so let's do nothing
if (daoID == 0) {
return;
}

verifyDaoType(daoID);

EOS_CHECK(
Member::isMember(*this, daoID, from),
"Sender is not a member of the DAO"
)
// Allow redeemptions from users that are not members, we might want to disable this
// EOS_CHECK(
// Member::isMember(*this, daoID, from),
// "Sender is not a member of the DAO"
// )

auto member = Member(*this, getMemberID(from));

Expand Down
Loading