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

Burn interest on PaybackWithCollateral #1455

Merged
merged 12 commits into from
Sep 12, 2022
86 changes: 43 additions & 43 deletions src/masternodes/govvariables/attributes.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -125,19 +125,19 @@ 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},
{"loan_payback_collateral", TokenKeys::LoanPaybackCollateral},
{"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},
{"payback_dfi", TokenKeys::PaybackDFI},
{"payback_dfi_fee_pct", TokenKeys::PaybackDFIFeePCT},
{"loan_payback", TokenKeys::LoanPayback},
{"loan_payback_fee_pct", TokenKeys::LoanPaybackFeePCT},
{"loan_payback_collateral", TokenKeys::LoanPaybackCollateral},
{"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 Down Expand Up @@ -168,22 +168,22 @@ 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::LoanPaybackCollateral, "loan_payback_collateral"},
{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"},
{TokenKeys::PaybackDFI, "payback_dfi"},
{TokenKeys::PaybackDFIFeePCT, "payback_dfi_fee_pct"},
{TokenKeys::LoanPayback, "loan_payback"},
{TokenKeys::LoanPaybackFeePCT, "loan_payback_fee_pct"},
{TokenKeys::LoanPaybackCollateral, "loan_payback_collateral"},
{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 @@ -345,19 +345,19 @@ 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::LoanPaybackCollateral, VerifyBool},
{TokenKeys::DexInFeePct, VerifyPct},
{TokenKeys::DexOutFeePct, VerifyPct},
{TokenKeys::FixedIntervalPriceId, VerifyCurrencyPair},
{TokenKeys::LoanCollateralEnabled, VerifyBool},
{TokenKeys::LoanCollateralFactor, VerifyPositiveFloat},
{TokenKeys::LoanMintingEnabled, VerifyBool},
{TokenKeys::LoanMintingInterest, VerifyFloat},
{TokenKeys::DFIP2203Enabled, VerifyBool},
{TokenKeys::PaybackDFI, VerifyBool},
{TokenKeys::PaybackDFIFeePCT, VerifyPct},
{TokenKeys::LoanPayback, VerifyBool},
{TokenKeys::LoanPaybackFeePCT, VerifyPct},
{TokenKeys::LoanPaybackCollateral, VerifyBool},
{TokenKeys::DexInFeePct, VerifyPct},
{TokenKeys::DexOutFeePct, VerifyPct},
{TokenKeys::FixedIntervalPriceId, VerifyCurrencyPair},
{TokenKeys::LoanCollateralEnabled, VerifyBool},
{TokenKeys::LoanCollateralFactor, VerifyPositiveFloat},
{TokenKeys::LoanMintingEnabled, VerifyBool},
{TokenKeys::LoanMintingInterest, VerifyFloat},
{TokenKeys::DFIP2203Enabled, VerifyBool},
}
},
{
Expand Down Expand Up @@ -1209,7 +1209,7 @@ Res ATTRIBUTES::Apply(CCustomCSView & mnview, const uint32_t height)
}
}
} else if (attrV0->key == TokenKeys::LoanCollateralFactor) {
if (height >= Params().GetConsensus().FortCanningEpilogueHeight) {
if (height >= static_cast<uint32_t>(Params().GetConsensus().FortCanningEpilogueHeight)) {
std::set<CAmount> ratio;
mnview.ForEachLoanScheme([&ratio](const std::string &identifier, const CLoanSchemeData &data) {
ratio.insert(data.ratio);
Expand Down
68 changes: 34 additions & 34 deletions src/masternodes/govvariables/attributes.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,17 +37,17 @@ enum OracleIDs : uint8_t {
};

enum EconomyKeys : uint8_t {
PaybackDFITokens = 'a',
PaybackTokens = 'b',
DFIP2203Current = 'c',
DFIP2203Burned = 'd',
DFIP2203Minted = 'e',
DFIP2206FCurrent = 'f',
DFIP2206FBurned = 'g',
DFIP2206FMinted = 'h',
DexTokens = 'i',
NegativeInt = 'j',
NegativeIntCurrent= 'k',
PaybackDFITokens = 'a',
PaybackTokens = 'b',
DFIP2203Current = 'c',
DFIP2203Burned = 'd',
DFIP2203Minted = 'e',
DFIP2206FCurrent = 'f',
DFIP2206FBurned = 'g',
DFIP2206FMinted = 'h',
DexTokens = 'i',
NegativeInt = 'j',
NegativeIntCurrent = 'k',
};

enum DFIPKeys : uint8_t {
Expand All @@ -56,28 +56,28 @@ enum DFIPKeys : uint8_t {
MinSwap = 'c',
RewardPct = 'd',
BlockPeriod = 'e',
DUSDInterestBurn = 'g',
DUSDLoanBurn = 'h',
DUSDInterestBurn = 'g',
DUSDLoanBurn = 'h',
StartBlock = 'i',
};

enum TokenKeys : uint8_t {
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',
LoanPaybackCollateral = 'p',
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',
LoanPaybackCollateral = 'p',
};

enum PoolKeys : uint8_t {
Expand All @@ -88,7 +88,7 @@ enum PoolKeys : uint8_t {
};

struct CDataStructureV0 {
uint8_t type;
uint8_t type;
uint32_t typeId;
uint32_t key;
uint32_t keyId;
Expand Down Expand Up @@ -188,11 +188,11 @@ enum FeeDirValues : uint8_t {
Out
};

using CDexBalances = std::map<DCT_ID, CDexTokenInfo>;
using OracleSplits = std::map<uint32_t, int32_t>;
using CDexBalances = std::map<DCT_ID, CDexTokenInfo>;
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 = std::variant<CDataStructureV0, CDataStructureV1>;
using AscendantValue = std::pair<uint32_t, std::string>;
using CAttributeType = std::variant<CDataStructureV0, CDataStructureV1>;
using CAttributeValue = std::variant<bool, CAmount, CBalances, CTokenPayback, CTokenCurrencyPair, OracleSplits, DescendantValue, AscendantValue, CFeeDir, CDexBalances>;

void TrackNegativeInterest(CCustomCSView& mnview, const CTokenAmount& amount);
Expand Down
56 changes: 41 additions & 15 deletions src/masternodes/mn_checks.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4478,7 +4478,7 @@ Res PaybackWithCollateral(CCustomCSView& view, const CVaultData& vault, const CV
if (!attributes)
return Res::Err("Attributes unavailable");

auto dUsdToken = view.GetToken("DUSD");
const auto dUsdToken = view.GetToken("DUSD");
if (!dUsdToken)
return Res::Err("Cannot find token DUSD");

Expand All @@ -4504,43 +4504,58 @@ Res PaybackWithCollateral(CCustomCSView& view, const CVaultData& vault, const CV
}
const auto& loanDUSD = loanAmounts->balances.at(dUsdToken->first);

auto rate = view.GetInterestRate(vaultId, dUsdToken->first, height);
const auto rate = view.GetInterestRate(vaultId, dUsdToken->first, height);
if (!rate)
return Res::Err("Cannot get interest rate for this token (DUSD)!");
auto subInterest = TotalInterest(*rate, height);
const auto subInterest = TotalInterest(*rate, height);

Res res{};
CAmount subLoanAmount{0};
CAmount subCollateralAmount{0};
// Edge case where interest is greater than collateral
CAmount burnAmount{0};

// Case where interest > collateral: decrease interest, wipe collateral.
if (subInterest > collateralDUSD) {
subCollateralAmount = collateralDUSD;

res = view.SubVaultCollateral(vaultId, {dUsdToken->first, subCollateralAmount});
if (!res)
return res;
if (!res) return res;

res = view.DecreaseInterest(height, vaultId, vault.schemeId, dUsdToken->first, 0, subCollateralAmount);
if (!res)
return res;
if (!res) return res;

burnAmount = subCollateralAmount;
} else {
// Postive interest: Loan + interest > collateral.
// Negative interest: Loan - abs(interest) > collateral.
if (loanDUSD + subInterest > collateralDUSD) {
subLoanAmount = collateralDUSD - subInterest;
subCollateralAmount = collateralDUSD;
} else {
// Common case: Collateral > loans.
subLoanAmount = loanDUSD;
subCollateralAmount = loanDUSD + subInterest;
}

res = view.SubLoanToken(vaultId, {dUsdToken->first, subLoanAmount});
if (!res)
return res;
if (subLoanAmount > 0) {
res = view.SubLoanToken(vaultId, {dUsdToken->first, subLoanAmount});
if (!res) return res;
}

res = view.SubVaultCollateral(vaultId, {dUsdToken->first,subCollateralAmount});
if (!res)
return res;
if (subCollateralAmount > 0) {
res = view.SubVaultCollateral(vaultId, {dUsdToken->first,subCollateralAmount});
if (!res) return res;
}

view.ResetInterest(height, vaultId, vault.schemeId, dUsdToken->first);
burnAmount = subInterest;
}


if (burnAmount > 0)
{
res = view.AddBalance(Params().GetConsensus().burnAddress, {dUsdToken->first, burnAmount});
if (!res) return res;
}

// Guard against liquidation
Expand All @@ -4553,11 +4568,22 @@ Res PaybackWithCollateral(CCustomCSView& view, const CVaultData& vault, const CV
if (!collateralsLoans)
return std::move(collateralsLoans);

// The check is required to do a ratio check safe guard, or the vault of ratio is unreliable.
// This can later be removed, if all edge cases of price deviations and max collateral factor for DUSD (1.5 currently)
// can be tested for economical stability. Taking the safer approach for now.
if (!IsVaultPriceValid(view, vaultId, height))
return Res::Err("Cannot payback vault with non-DUSD assets while any of the asset's price is invalid");

const auto scheme = view.GetLoanScheme(vault.schemeId);
if (collateralsLoans.val->ratio() < scheme->ratio)
return Res::Err("Vault does not have enough collateralization ratio defined by loan scheme - %d < %d", collateralsLoans.val->ratio(), scheme->ratio);

return view.SubMintedTokens(dUsdToken->first, subCollateralAmount);
if (subCollateralAmount > 0) {
res = view.SubMintedTokens(dUsdToken->first, subCollateralAmount);
if (!res) return res;
}

return Res::Ok();
}

Res storeGovVars(const CGovernanceHeightMessage& obj, CCustomCSView& view) {
Expand Down
3 changes: 2 additions & 1 deletion src/masternodes/rpc_accounts.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1875,7 +1875,8 @@ UniValue getburninfo(const JSONRPCRequest& request) {
}
// withdraw burn
if (value.category == uint8_t(CustomTxType::PaybackLoan)
|| value.category == uint8_t(CustomTxType::PaybackLoanV2)) {
|| value.category == uint8_t(CustomTxType::PaybackLoanV2)
|| value.category == uint8_t(CustomTxType::PaybackWithCollateral)) {
for (const auto& [id, amount] : value.diff) {
paybackFee.Add({id, amount});
}
Expand Down
Loading