Skip to content

Commit

Permalink
Move loan and collateral token to Gov var
Browse files Browse the repository at this point in the history
  • Loading branch information
Bushstar committed May 18, 2022
1 parent e327801 commit b980af0
Show file tree
Hide file tree
Showing 18 changed files with 869 additions and 213 deletions.
156 changes: 122 additions & 34 deletions src/masternodes/govvariables/attributes.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,23 +6,22 @@

#include <masternodes/accountshistory.h> /// CAccountsHistoryWriter
#include <masternodes/masternodes.h> /// CCustomCSView
#include <masternodes/mn_checks.h> /// GetAggregatePrice
#include <masternodes/mn_checks.h> /// CustomTxType

#include <core_io.h> /// ValueFromAmount
#include <util/strencodings.h>

extern UniValue AmountsToJSON(TAmounts const & diffs);

template<typename T>
static std::string KeyBuilder(const T& value){
std::ostringstream oss;
oss << value;
return oss.str();
}

template<typename T, typename ... Args >
static std::string KeyBuilder(const T& value, const Args& ... args){
return KeyBuilder(value) + '/' + KeyBuilder(args...);
static inline std::string trim_all_ws(std::string s) {
s.erase(s.begin(), std::find_if(s.begin(), s.end(), [](unsigned char ch) {
return !std::isspace(ch);
}));
s.erase(std::find_if(s.rbegin(), s.rend(), [](unsigned char ch) {
return !std::isspace(ch);
}).base(), s.end());
return s;
}

static std::vector<std::string> KeyBreaker(const std::string& str, const char delim = '/'){
Expand Down Expand Up @@ -116,13 +115,18 @@ const std::map<uint8_t, std::map<std::string, uint8_t>>& ATTRIBUTES::allowedKeys
static const std::map<uint8_t, std::map<std::string, uint8_t>> keys{
{
AttributeTypes::Token, {
{"payback_dfi", TokenKeys::PaybackDFI},
{"payback_dfi_fee_pct", TokenKeys::PaybackDFIFeePCT},
{"loan_payback", TokenKeys::LoanPayback},
{"loan_payback_fee_pct",TokenKeys::LoanPaybackFeePCT},
{"dex_in_fee_pct", TokenKeys::DexInFeePct},
{"dex_out_fee_pct", TokenKeys::DexOutFeePct},
{"dfip2203", TokenKeys::DFIP2203Enabled},
{"payback_dfi", TokenKeys::PaybackDFI},
{"payback_dfi_fee_pct", TokenKeys::PaybackDFIFeePCT},
{"loan_payback", TokenKeys::LoanPayback},
{"loan_payback_fee_pct", TokenKeys::LoanPaybackFeePCT},
{"dex_in_fee_pct", TokenKeys::DexInFeePct},
{"dex_out_fee_pct", TokenKeys::DexOutFeePct},
{"dfip2203", TokenKeys::DFIP2203Enabled},
{"fixed_interval_price_id", TokenKeys::FixedIntervalPriceId},
{"loan_collateral_enabled", TokenKeys::LoanCollateralEnabled},
{"loan_collateral_factor", TokenKeys::LoanCollateralFactor},
{"loan_minting_enabled", TokenKeys::LoanMintingEnabled},
{"loan_minting_interest", TokenKeys::LoanMintingInterest},
}
},
{
Expand All @@ -149,6 +153,11 @@ const std::map<TokenKeys, CAttributeValue> ATTRIBUTES::tokenKeysToType {
{TokenKeys::PaybackDFIFeePCT, CAmount{}},
{TokenKeys::DexInFeePct, CAmount{}},
{TokenKeys::DexOutFeePct, CAmount{}},
{TokenKeys::FixedIntervalPriceId, CTokenCurrencyPair{}},
{TokenKeys::LoanCollateralEnabled, bool{}},
{TokenKeys::LoanCollateralFactor, CAmount{}},
{TokenKeys::LoanMintingEnabled, bool{}},
{TokenKeys::LoanMintingInterest, CAmount{}},
};

const std::map<PoolKeys, CAttributeValue> ATTRIBUTES::poolKeysToType {
Expand All @@ -160,16 +169,21 @@ const std::map<uint8_t, std::map<uint8_t, std::string>>& ATTRIBUTES::displayKeys
static const std::map<uint8_t, std::map<uint8_t, std::string>> keys{
{
AttributeTypes::Token, {
{TokenKeys::PaybackDFI, "payback_dfi"},
{TokenKeys::PaybackDFIFeePCT, "payback_dfi_fee_pct"},
{TokenKeys::LoanPayback, "loan_payback"},
{TokenKeys::LoanPaybackFeePCT,"loan_payback_fee_pct"},
{TokenKeys::DexInFeePct, "dex_in_fee_pct"},
{TokenKeys::DexOutFeePct, "dex_out_fee_pct"},
{TokenKeys::DFIP2203Enabled, "dfip2203"},
{TokenKeys::Ascendant, "ascendant"},
{TokenKeys::Descendant, "descendant"},
{TokenKeys::Epitaph, "epitaph"},
{TokenKeys::PaybackDFI, "payback_dfi"},
{TokenKeys::PaybackDFIFeePCT, "payback_dfi_fee_pct"},
{TokenKeys::LoanPayback, "loan_payback"},
{TokenKeys::LoanPaybackFeePCT, "loan_payback_fee_pct"},
{TokenKeys::DexInFeePct, "dex_in_fee_pct"},
{TokenKeys::DexOutFeePct, "dex_out_fee_pct"},
{TokenKeys::FixedIntervalPriceId, "fixed_interval_price_id"},
{TokenKeys::LoanCollateralEnabled, "loan_collateral_enabled"},
{TokenKeys::LoanCollateralFactor, "loan_collateral_factor"},
{TokenKeys::LoanMintingEnabled, "loan_minting_enabled"},
{TokenKeys::LoanMintingInterest, "loan_minting_interest"},
{TokenKeys::DFIP2203Enabled, "dfip2203"},
{TokenKeys::Ascendant, "ascendant"},
{TokenKeys::Descendant, "descendant"},
{TokenKeys::Epitaph, "epitaph"},
}
},
{
Expand Down Expand Up @@ -278,20 +292,42 @@ static ResVal<CAttributeValue> VerifySplit(const std::string& str) {
return {splits, Res::Ok()};
}

static ResVal<CAttributeValue> VerifyCurrencyPair(const std::string& str) {
const auto value = KeyBreaker(str);
if (value.size() != 2) {
return Res::Err("Exactly two entires expected for currency pair");
}
auto token = trim_all_ws(value[0]).substr(0, CToken::MAX_TOKEN_SYMBOL_LENGTH);
auto currency = trim_all_ws(value[1]).substr(0, CToken::MAX_TOKEN_SYMBOL_LENGTH);
if (token.empty() || currency.empty()) {
return Res::Err("Empty token / currency");
}
return {CTokenCurrencyPair{token, currency}, Res::Ok()};
}

static bool VerifyToken(const CCustomCSView& view, const uint32_t id) {
return view.GetToken(DCT_ID{id}).has_value();
}

const std::map<uint8_t, std::map<uint8_t,
std::function<ResVal<CAttributeValue>(const std::string&)>>>& ATTRIBUTES::parseValue() {

static const std::map<uint8_t, std::map<uint8_t,
std::function<ResVal<CAttributeValue>(const std::string&)>>> parsers{
{
AttributeTypes::Token, {
{TokenKeys::PaybackDFI, VerifyBool},
{TokenKeys::PaybackDFIFeePCT, VerifyPct},
{TokenKeys::LoanPayback, VerifyBool},
{TokenKeys::LoanPaybackFeePCT,VerifyPct},
{TokenKeys::DexInFeePct, VerifyPct},
{TokenKeys::DexOutFeePct, VerifyPct},
{TokenKeys::DFIP2203Enabled, VerifyBool},
{TokenKeys::PaybackDFI, VerifyBool},
{TokenKeys::PaybackDFIFeePCT, VerifyPct},
{TokenKeys::LoanPayback, VerifyBool},
{TokenKeys::LoanPaybackFeePCT, VerifyPct},
{TokenKeys::DexInFeePct, VerifyPct},
{TokenKeys::DexOutFeePct, VerifyPct},
{TokenKeys::FixedIntervalPriceId, VerifyCurrencyPair},
{TokenKeys::LoanCollateralEnabled, VerifyBool},
{TokenKeys::LoanCollateralFactor, VerifyPct},
{TokenKeys::LoanMintingEnabled, VerifyBool},
{TokenKeys::LoanMintingInterest, VerifyFloat},
{TokenKeys::DFIP2203Enabled, VerifyBool},
}
},
{
Expand Down Expand Up @@ -658,6 +694,8 @@ UniValue ATTRIBUTES::Export() const {
ret.pushKV(key, KeyBuilder(descendantPair->first, descendantPair->second));
} else if (const auto& ascendantPair = boost::get<AscendantValue>(&attribute.second)) {
ret.pushKV(key, KeyBuilder(ascendantPair->first, ascendantPair->second));
} else if (auto currencyPair = boost::get<CTokenCurrencyPair>(&attribute.second)) {
ret.pushKV(key, currencyPair->first + '/' + currencyPair->second);
}
} catch (const std::out_of_range&) {
// Should not get here, that's mean maps are mismatched
Expand Down Expand Up @@ -706,6 +744,31 @@ Res ATTRIBUTES::Validate(const CCustomCSView & view) const
return Res::Err("No such token (%d)", attrV0->typeId);
}
break;
case TokenKeys::LoanCollateralEnabled:
case TokenKeys::LoanCollateralFactor:
case TokenKeys::LoanMintingEnabled:
case TokenKeys::LoanMintingInterest: {
if (view.GetLastHeight() < Params().GetConsensus().FortCanningGreenHeight) {
return Res::Err("Cannot be set before FortCanningGreen");
}
if (!VerifyToken(view, attrV0->typeId)) {
return Res::Err("No such token (%d)", attrV0->typeId);
}
CDataStructureV0 intervalPriceKey{AttributeTypes::Token, attrV0->typeId,
TokenKeys::FixedIntervalPriceId};
if (GetValue(intervalPriceKey, CTokenCurrencyPair{}) == CTokenCurrencyPair{}) {
return Res::Err("Fixed interval price currency pair must be set first");
}
break;
}
case TokenKeys::FixedIntervalPriceId:
if (view.GetLastHeight() < Params().GetConsensus().FortCanningGreenHeight) {
return Res::Err("Cannot be set before FortCanningGreen");
}
if (!VerifyToken(view, attrV0->typeId)) {
return Res::Err("No such token (%d)", attrV0->typeId);
}
break;
case TokenKeys::DFIP2203Enabled:
if (view.GetLastHeight() < Params().GetConsensus().FortCanningRoadHeight) {
return Res::Err("Cannot be set before FortCanningRoad");
Expand Down Expand Up @@ -834,6 +897,31 @@ Res ATTRIBUTES::Apply(CCustomCSView & mnview, const uint32_t height)
return res;
}
}
if (attrV0->key == TokenKeys::FixedIntervalPriceId) {
if (const auto &currencyPair = boost::get<CTokenCurrencyPair>(&attribute.second)) {
// Already exists, skip.
if (mnview.GetFixedIntervalPrice(*currencyPair)) {
continue;
} else if (!OraclePriceFeed(mnview, *currencyPair)) {
return Res::Err("Price feed %s/%s does not belong to any oracle", currencyPair->first,
currencyPair->second);
}
CFixedIntervalPrice fixedIntervalPrice;
fixedIntervalPrice.priceFeedId = *currencyPair;
fixedIntervalPrice.timestamp = time;
fixedIntervalPrice.priceRecord[1] = -1;
const auto aggregatePrice = GetAggregatePrice(mnview,
fixedIntervalPrice.priceFeedId.first,
fixedIntervalPrice.priceFeedId.second,
time);
if (aggregatePrice) {
fixedIntervalPrice.priceRecord[1] = aggregatePrice;
}
mnview.SetFixedIntervalPrice(fixedIntervalPrice);
} else {
return Res::Err("Unrecognised value for FixedIntervalPriceId");
}
}
if (attrV0->key == TokenKeys::DFIP2203Enabled) {

// Skip on block period change to avoid refunding and erasing entries.
Expand Down
55 changes: 37 additions & 18 deletions src/masternodes/govvariables/attributes.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#include <amount.h>
#include <masternodes/balances.h>
#include <masternodes/gv.h>
#include <masternodes/oracles.h>

enum VersionTypes : uint8_t {
v0 = 0,
Expand Down Expand Up @@ -50,16 +51,21 @@ enum DFIPKeys : uint8_t {
};

enum TokenKeys : uint8_t {
PaybackDFI = 'a',
PaybackDFIFeePCT = 'b',
LoanPayback = 'c',
LoanPaybackFeePCT = 'd',
DexInFeePct = 'e',
DexOutFeePct = 'f',
DFIP2203Enabled = 'g',
Ascendant = 'm',
Descendant = 'n',
Epitaph = 'o',
PaybackDFI = 'a',
PaybackDFIFeePCT = 'b',
LoanPayback = 'c',
LoanPaybackFeePCT = 'd',
DexInFeePct = 'e',
DexOutFeePct = 'f',
DFIP2203Enabled = 'g',
FixedIntervalPriceId = 'h',
LoanCollateralEnabled = 'i',
LoanCollateralFactor = 'j',
LoanMintingEnabled = 'k',
LoanMintingInterest = 'l',
Ascendant = 'm',
Descendant = 'n',
Epitaph = 'o',
};

enum PoolKeys : uint8_t {
Expand Down Expand Up @@ -127,7 +133,7 @@ using OracleSplits = std::map<uint32_t, int32_t>;
using DescendantValue = std::pair<uint32_t, int32_t>;
using AscendantValue = std::pair<uint32_t, std::string>;
using CAttributeType = boost::variant<CDataStructureV0, CDataStructureV1>;
using CAttributeValue = boost::variant<bool, CAmount, CBalances, CTokenPayback, OracleSplits, DescendantValue, AscendantValue>;
using CAttributeValue = boost::variant<bool, CAmount, CBalances, CTokenPayback, CTokenCurrencyPair, OracleSplits, DescendantValue, AscendantValue>;

class ATTRIBUTES : public GovVariable, public AutoRegistrator<GovVariable, ATTRIBUTES>
{
Expand Down Expand Up @@ -163,6 +169,19 @@ class ATTRIBUTES : public GovVariable, public AutoRegistrator<GovVariable, ATTRI
return attributes.count(key) > 0;
}

template<typename C, typename K>
void ForEach(const C& callback, const K& key) const {
static_assert(std::is_convertible_v<K, CAttributeType>);
static_assert(std::is_invocable_r_v<bool, C, K, CAttributeValue>);
for (auto it = attributes.lower_bound(key); it != attributes.end(); ++it) {
if (auto attrV0 = boost::get<K>(&it->first)) {
if (!std::invoke(callback, *attrV0, it->second)) {
break;
}
}
}
}

ADD_OVERRIDE_VECTOR_SERIALIZE_METHODS
ADD_OVERRIDE_SERIALIZE_METHODS(CDataStream)

Expand All @@ -172,7 +191,14 @@ class ATTRIBUTES : public GovVariable, public AutoRegistrator<GovVariable, ATTRI
}

std::map<CAttributeType, CAttributeValue> attributes;
uint32_t time{0};

// For formatting in export
static const std::map<uint8_t, std::string>& displayVersions();
static const std::map<uint8_t, std::string>& displayTypes();
static const std::map<uint8_t, std::string>& displayParamsIDs();
static const std::map<uint8_t, std::string>& displayOracleIDs();
static const std::map<uint8_t, std::map<uint8_t, std::string>>& displayKeys();
static const std::map<TokenKeys, CAttributeValue> tokenKeysToType;
static const std::map<PoolKeys, CAttributeValue> poolKeysToType;

Expand All @@ -189,13 +215,6 @@ class ATTRIBUTES : public GovVariable, public AutoRegistrator<GovVariable, ATTRI
static const std::map<uint8_t, std::map<uint8_t,
std::function<ResVal<CAttributeValue>(const std::string&)>>>& parseValue();

// For formatting in export
static const std::map<uint8_t, std::string>& displayVersions();
static const std::map<uint8_t, std::string>& displayTypes();
static const std::map<uint8_t, std::string>& displayParamsIDs();
static const std::map<uint8_t, std::string>& displayOracleIDs();
static const std::map<uint8_t, std::map<uint8_t, std::string>>& displayKeys();

Res ProcessVariable(const std::string& key, const std::string& value,
std::function<Res(const CAttributeType&, const CAttributeValue&)> applyVariable);
Res RefundFuturesContracts(CCustomCSView &mnview, const uint32_t height, const uint32_t tokenID = std::numeric_limits<uint32_t>::max());
Expand Down
Loading

0 comments on commit b980af0

Please sign in to comment.