From 3090db1d630a7205e9bbd64f3508791320aba163 Mon Sep 17 00:00:00 2001 From: Peter Bushnell Date: Tue, 20 Sep 2022 09:11:52 +0100 Subject: [PATCH 01/11] Correct minted tracking error --- src/masternodes/mn_checks.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/masternodes/mn_checks.cpp b/src/masternodes/mn_checks.cpp index 2689a05f1f7..eeef5282c0f 100644 --- a/src/masternodes/mn_checks.cpp +++ b/src/masternodes/mn_checks.cpp @@ -3539,14 +3539,14 @@ class CCustomTxApplyVisitor : public CCustomTxVisitor if (paybackTokenId == loanTokenId) { + res = mnview.SubMintedTokens(loanTokenId, subInterest > 0 ? subLoan : subLoan + subInterest); + if (!res) + return res; + // If interest was negative remove it from sub amount if (height >= static_cast(consensus.FortCanningEpilogueHeight) && subInterest < 0) subLoan += subInterest; - res = mnview.SubMintedTokens(loanTokenId, subLoan); - if (!res) - return res; - // Do not sub balance if negative interest fully negates the current loan amount if (!(subInterest < 0 && std::abs(subInterest) >= currentLoanAmount)) { From 130a0455f457ad0982a69456229e6e4c3937b97e Mon Sep 17 00:00:00 2001 From: Peter Bushnell Date: Tue, 20 Sep 2022 13:55:33 +0100 Subject: [PATCH 02/11] Track DUSD loan amount on consensus --- src/masternodes/loan.cpp | 12 +++++++ src/masternodes/loan.h | 10 ++++++ src/masternodes/mn_checks.cpp | 4 +++ src/validation.cpp | 66 +++++++++++++++++++++++++++++++++++ 4 files changed, 92 insertions(+) diff --git a/src/masternodes/loan.cpp b/src/masternodes/loan.cpp index 1737be7c1fc..b82a9e32b78 100644 --- a/src/masternodes/loan.cpp +++ b/src/masternodes/loan.cpp @@ -301,6 +301,18 @@ void CLoanView::WriteInterestRate(const std::pair& pair, const } } +std::map CLoanView::GetExcessLoans() const { + std::map excessLoans; + if (Read(ExcessLoanTokens::prefix(), excessLoans)) { + return excessLoans; + } + return {}; +} + +bool CLoanView::SetExcessLoans(const std::map& excessLoans) { + return Write(ExcessLoanTokens::prefix(), excessLoans); +} + Res CLoanView::IncreaseInterest(const uint32_t height, const CVaultId& vaultId, const std::string& loanSchemeID, const DCT_ID id, const CAmount tokenInterest, const CAmount loanIncreased) { const auto scheme = GetLoanScheme(loanSchemeID); diff --git a/src/masternodes/loan.h b/src/masternodes/loan.h index a19b70f0877..2535e171bdb 100644 --- a/src/masternodes/loan.h +++ b/src/masternodes/loan.h @@ -480,9 +480,18 @@ class CLoanView : public virtual CStorageView { Res SetLoanLiquidationPenalty(CAmount penalty); CAmount GetLoanLiquidationPenalty(); + [[nodiscard]] std::map GetExcessLoans() const; + bool SetExcessLoans(const std::map& excessLoans); + [[nodiscard]] virtual std::optional GetLoanTokenFromAttributes(const DCT_ID& id) const = 0; [[nodiscard]] virtual std::optional GetCollateralTokenFromAttributes(const DCT_ID& id) const = 0; + enum ExcessLoanType : uint8_t { + BatchRounding, + AuctionInterest, + DFIPayback, + }; + struct LoanSetCollateralTokenCreationTx { static constexpr uint8_t prefix() { return 0x10; } }; struct LoanSetCollateralTokenKey { static constexpr uint8_t prefix() { return 0x11; } }; struct LoanSetLoanTokenCreationTx { static constexpr uint8_t prefix() { return 0x12; } }; @@ -496,6 +505,7 @@ class CLoanView : public virtual CStorageView { struct LoanLiquidationPenalty { static constexpr uint8_t prefix() { return 0x1A; } }; struct LoanInterestV2ByVault { static constexpr uint8_t prefix() { return 0x1B; } }; struct LoanInterestV3ByVault { static constexpr uint8_t prefix() { return 0x1C; } }; + struct ExcessLoanTokens { static constexpr uint8_t prefix() { return 0x1D; } }; }; #endif // DEFI_MASTERNODES_LOAN_H diff --git a/src/masternodes/mn_checks.cpp b/src/masternodes/mn_checks.cpp index ed1f612a1a8..ec9a76a2dd8 100644 --- a/src/masternodes/mn_checks.cpp +++ b/src/masternodes/mn_checks.cpp @@ -3607,6 +3607,10 @@ class CCustomTxApplyVisitor : public CCustomTxVisitor CDataStructureV0 liveKey{AttributeTypes::Live, ParamIDs::Economy, EconomyKeys::PaybackDFITokens}; auto balances = attributes->GetValue(liveKey, CBalances{}); + auto excessLoans = mnview.GetExcessLoans(); + excessLoans[static_cast(CLoanView::ExcessLoanType::DFIPayback)].Add({loanTokenId, subLoan}); + mnview.SetExcessLoans(excessLoans); + balances.Add(CTokenAmount{loanTokenId, subAmount}); balances.Add(CTokenAmount{paybackTokenId, penalty}); attributes->SetValue(liveKey, balances); diff --git a/src/validation.cpp b/src/validation.cpp index 93f72596bd1..d8f8dfd6b1f 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -2491,6 +2491,54 @@ bool CChainState::ConnectBlock(const CBlock& block, CValidationState& state, CBl assert(*pindex->phashBlock == block.GetHash()); int64_t nTimeStart = GetTimeMicros(); + if (const auto token = mnview.GetToken("DUSD")) { + CAmount totalDUSD{}; + mnview.ForEachLoanTokenAmount([&](const CVaultId& vaultId, const CBalances& balances){ + for (const auto& [tokenId, amount] : balances.balances) { + if (tokenId == token->first) { + totalDUSD += amount; + } + } + return true; + }); + + mnview.ForEachVaultAuction([&](const CVaultId& vaultId, const CAuctionData& data) { + for (uint32_t i = 0; i < data.batchCount; ++i) { + if (const auto batch = mnview.GetAuctionBatch({vaultId, i}); batch && batch->loanAmount.nTokenId == token->first) { + totalDUSD += batch->loanAmount.nValue - batch->loanInterest; + } + } + return true; + }, pindex->nHeight); + + auto excessLoans = mnview.GetExcessLoans(); + + const CDataStructureV0 mintedKey{AttributeTypes::Live, ParamIDs::Economy, EconomyKeys::DFIP2203Minted}; + const CDataStructureV0 negativeInterestKey{AttributeTypes::Live, ParamIDs::Economy, EconomyKeys::NegativeInt}; + const auto attributes = mnview.GetAttributes(); + auto minted = attributes->GetValue(mintedKey, CBalances{}); + auto negativeBalances = attributes->GetValue(negativeInterestKey, CBalances{}); + + totalDUSD = totalDUSD + - excessLoans[CLoanView::ExcessLoanType::BatchRounding].balances[token->first] + - excessLoans[CLoanView::ExcessLoanType::AuctionInterest].balances[token->first] + + excessLoans[CLoanView::ExcessLoanType::DFIPayback].balances[token->first] + + minted.balances[token->first] + + negativeBalances.balances[token->first]; + + if (token->second->minted != totalDUSD) { + return state.Invalid( + ValidationInvalidReason::CONSENSUS, + error("%s: Block height %d mismatch DUSD minted %d DUSD loan amount %d", + __func__, + pindex->nHeight, + GetDecimaleString(token->second->minted + excessLoans[CLoanView::ExcessLoanType::BatchRounding].balances[token->first] + excessLoans[CLoanView::ExcessLoanType::AuctionInterest].balances[token->first]), + GetDecimaleString(totalDUSD + excessLoans[CLoanView::ExcessLoanType::DFIPayback].balances[token->first] + minted.balances[token->first] + negativeBalances.balances[token->first]), + REJECT_INVALID, + "token-balance-mismatch")); + } + } + // Interrupt on hash or height requested. Invalidate the block. if (StopOrInterruptConnect(pindex, state)) return false; @@ -3399,18 +3447,33 @@ void CChainState::ProcessLoanEvents(const CBlockIndex* pindex, CCustomCSView& ca auto batches = CollectAuctionBatches(*collateral.val, collaterals.balances, loanTokens->balances); // Now, let's add the remaining amounts and store the batch. + CBalances totalLoanInBatches{}; for (auto i = 0u; i < batches.size(); i++) { auto& batch = batches[i]; + totalLoanInBatches.Add(batch.loanAmount); auto tokenId = batch.loanAmount.nTokenId; auto interest = totalInterest.balances[tokenId]; if (interest > 0) { auto balance = loanTokens->balances[tokenId]; auto interestPart = DivideAmounts(batch.loanAmount.nValue, balance); batch.loanInterest = MultiplyAmounts(interestPart, interest); + totalLoanInBatches.Sub({tokenId, batch.loanInterest}); } cache.StoreAuctionBatch({vaultId, i}, batch); } + // Check if more than loan amount was generated. + for (const auto& [tokenId, amount] : loanTokens->balances) { + if (totalLoanInBatches.balances.count(tokenId)) { + const auto interest = totalInterest.balances.count(tokenId) ? totalInterest.balances[tokenId] : 0; + if (totalLoanInBatches.balances[tokenId] > amount - interest) { + auto excessLoans = cache.GetExcessLoans(); + excessLoans[static_cast(CLoanView::ExcessLoanType::BatchRounding)].Add({tokenId, totalLoanInBatches.balances[tokenId] - (amount - interest)}); + cache.SetExcessLoans(excessLoans); + } + } + } + // All done. Ready to save the overall auction. cache.StoreAuction(vaultId, CAuctionData{ uint32_t(batches.size()), @@ -3494,6 +3557,9 @@ void CChainState::ProcessLoanEvents(const CBlockIndex* pindex, CCustomCSView& ca } else { // we should return loan including interest view.AddLoanToken(vaultId, batch->loanAmount); + auto excessLoans = cache.GetExcessLoans(); + excessLoans[static_cast(CLoanView::ExcessLoanType::AuctionInterest)].Add({batch->loanAmount.nTokenId, batch->loanInterest}); + cache.SetExcessLoans(excessLoans); if (auto token = view.GetLoanTokenByID(batch->loanAmount.nTokenId)) { view.IncreaseInterest(pindex->nHeight, vaultId, vault->schemeId, batch->loanAmount.nTokenId, token->interest, batch->loanAmount.nValue); } From d9b8325dd412887c1ceada5fadeb2fc85a8664fe Mon Sep 17 00:00:00 2001 From: Peter Bushnell Date: Tue, 20 Sep 2022 13:55:51 +0100 Subject: [PATCH 03/11] List differences in loan amounts --- src/masternodes/rpc_loan.cpp | 78 ++++++++++++++++++++++++++++++++++++ 1 file changed, 78 insertions(+) diff --git a/src/masternodes/rpc_loan.cpp b/src/masternodes/rpc_loan.cpp index 11e5a091839..db3b7538f60 100644 --- a/src/masternodes/rpc_loan.cpp +++ b/src/masternodes/rpc_loan.cpp @@ -4,6 +4,8 @@ extern UniValue tokenToJSON(CCustomCSView& view, DCT_ID const& id, CTokenImplementation const& token, bool verbose); extern std::pair GetFixedIntervalPriceBlocks(int currentHeight, const CCustomCSView &mnview); +extern UniValue AmountsToJSON(TAmounts const & diffs, AmountFormat format = AmountFormat::Symbol); +extern std::string tokenAmountString(CTokenAmount const& amount, AmountFormat format = AmountFormat::Symbol); UniValue setCollateralTokenToJSON(CCustomCSView& view, CLoanSetCollateralTokenImplementation const& collToken) { @@ -1617,6 +1619,81 @@ UniValue paybackwithcollateral(const JSONRPCRequest& request) { return signsend(rawTx, pwallet, optAuthTx)->GetHash().GetHex(); } +UniValue loanamountdifferences(const JSONRPCRequest& request) { + auto pwallet = GetWallet(request); + + RPCHelpMan{"loanamountdifferences", + "Returns the differences between token minted and total loan amounts in vaults\n", + {}, + RPCResult{ + "{...} (object) JSON object with loan token information\n" + }, + RPCExamples{ + HelpExampleCli("loanamountdifferences", "") + + HelpExampleRpc("loanamountdifferences", "") + }, + }.Check(request); + + if (auto res = GetRPCResultCache().TryGet(request)) return *res; + + LOCK(cs_main); + + const auto excessLoans = pcustomcsview->GetExcessLoans(); + + UniValue ret(UniValue::VARR); + + for (const auto& [key, balances] : excessLoans) { + UniValue retObj(UniValue::VOBJ); + switch(key) { + case CLoanView::ExcessLoanType::BatchRounding: { + UniValue obj(UniValue::VARR); + for (auto const &[tokenId, amount]: balances.balances) { + obj.push_back(tokenAmountString({tokenId, -amount})); + } + retObj.pushKV("BatchRounding", obj); + break; + } + case CLoanView::ExcessLoanType::AuctionInterest: { + UniValue obj(UniValue::VARR); + for (auto const &[tokenId, amount]: balances.balances) { + obj.push_back(tokenAmountString({tokenId, -amount})); + } + retObj.pushKV("AuctionInterest", obj); + break; + } + case CLoanView::ExcessLoanType::DFIPayback: { + UniValue obj(UniValue::VARR); + for (auto const &[tokenId, amount]: balances.balances) { + obj.push_back(tokenAmountString({tokenId, -amount})); + } + retObj.pushKV("DFIPayback", obj); + break; + } + } + ret.push_back(retObj); + } + + const CDataStructureV0 mintedKey{AttributeTypes::Live, ParamIDs::Economy, EconomyKeys::DFIP2203Minted}; + const CDataStructureV0 negativeInterestKey{AttributeTypes::Live, ParamIDs::Economy, EconomyKeys::NegativeInt}; + const auto attributes = pcustomcsview->GetAttributes(); + const auto minted = attributes->GetValue(mintedKey, CBalances{}); + const auto negativeBalances = attributes->GetValue(negativeInterestKey, CBalances{}); + + { + UniValue retObj(UniValue::VOBJ); + retObj.pushKV("Futures", AmountsToJSON(minted.balances)); + ret.push_back(retObj); + } + + { + UniValue retObj(UniValue::VOBJ); + retObj.pushKV("NegativeInterest", AmountsToJSON(negativeBalances.balances)); + ret.push_back(retObj); + } + + return GetRPCResultCache().Set(request, ret); +} + static const CRPCCommand commands[] = { // category name actor (function) params @@ -1639,6 +1716,7 @@ static const CRPCCommand commands[] = {"vault", "paybackwithcollateral", &paybackwithcollateral, {"vaultId"}}, {"loan", "getloaninfo", &getloaninfo, {}}, {"loan", "getinterest", &getinterest, {"id", "token"}}, + {"loan", "loanamountdifferences", &loanamountdifferences, {}}, }; void RegisterLoanRPCCommands(CRPCTable& tableRPC) { From 42b7fb5a79d8b225dfb3e14cc2f9a35f45373e38 Mon Sep 17 00:00:00 2001 From: Peter Bushnell Date: Thu, 22 Sep 2022 10:06:38 +0100 Subject: [PATCH 04/11] Fix errors in logging --- src/validation.cpp | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/src/validation.cpp b/src/validation.cpp index d8f8dfd6b1f..9fc1f804050 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -2492,11 +2492,11 @@ bool CChainState::ConnectBlock(const CBlock& block, CValidationState& state, CBl int64_t nTimeStart = GetTimeMicros(); if (const auto token = mnview.GetToken("DUSD")) { - CAmount totalDUSD{}; + CAmount loanDUSD{}, auctionDUSD{}; mnview.ForEachLoanTokenAmount([&](const CVaultId& vaultId, const CBalances& balances){ for (const auto& [tokenId, amount] : balances.balances) { if (tokenId == token->first) { - totalDUSD += amount; + loanDUSD += amount; } } return true; @@ -2505,7 +2505,7 @@ bool CChainState::ConnectBlock(const CBlock& block, CValidationState& state, CBl mnview.ForEachVaultAuction([&](const CVaultId& vaultId, const CAuctionData& data) { for (uint32_t i = 0; i < data.batchCount; ++i) { if (const auto batch = mnview.GetAuctionBatch({vaultId, i}); batch && batch->loanAmount.nTokenId == token->first) { - totalDUSD += batch->loanAmount.nValue - batch->loanInterest; + auctionDUSD += batch->loanAmount.nValue - batch->loanInterest; } } return true; @@ -2519,7 +2519,8 @@ bool CChainState::ConnectBlock(const CBlock& block, CValidationState& state, CBl auto minted = attributes->GetValue(mintedKey, CBalances{}); auto negativeBalances = attributes->GetValue(negativeInterestKey, CBalances{}); - totalDUSD = totalDUSD + const auto totalDUSD = loanDUSD + + auctionDUSD - excessLoans[CLoanView::ExcessLoanType::BatchRounding].balances[token->first] - excessLoans[CLoanView::ExcessLoanType::AuctionInterest].balances[token->first] + excessLoans[CLoanView::ExcessLoanType::DFIPayback].balances[token->first] @@ -2529,13 +2530,13 @@ bool CChainState::ConnectBlock(const CBlock& block, CValidationState& state, CBl if (token->second->minted != totalDUSD) { return state.Invalid( ValidationInvalidReason::CONSENSUS, - error("%s: Block height %d mismatch DUSD minted %d DUSD loan amount %d", + error("%s: Block height %d mismatch DUSD minted %s DUSD loan amount %s", __func__, pindex->nHeight, - GetDecimaleString(token->second->minted + excessLoans[CLoanView::ExcessLoanType::BatchRounding].balances[token->first] + excessLoans[CLoanView::ExcessLoanType::AuctionInterest].balances[token->first]), - GetDecimaleString(totalDUSD + excessLoans[CLoanView::ExcessLoanType::DFIPayback].balances[token->first] + minted.balances[token->first] + negativeBalances.balances[token->first]), - REJECT_INVALID, - "token-balance-mismatch")); + GetDecimaleString(token->second->minted), + GetDecimaleString(totalDUSD)), + REJECT_INVALID, + "token-balance-mismatch"); } } From 41ee6443552da4d1e2b24decd9e52b3daae6e322 Mon Sep 17 00:00:00 2001 From: Peter Bushnell Date: Thu, 22 Sep 2022 10:06:54 +0100 Subject: [PATCH 05/11] Track negative interest in collateral payback --- src/masternodes/mn_checks.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/masternodes/mn_checks.cpp b/src/masternodes/mn_checks.cpp index ec9a76a2dd8..df2916e5a3b 100644 --- a/src/masternodes/mn_checks.cpp +++ b/src/masternodes/mn_checks.cpp @@ -4571,6 +4571,8 @@ Res PaybackWithCollateral(CCustomCSView& view, const CVaultData& vault, const CV { res = view.AddBalance(Params().GetConsensus().burnAddress, {dUsdToken->first, burnAmount}); if (!res) return res; + } else { + TrackNegativeInterest(view, {dUsdToken->first, std::abs(burnAmount)}); } // Guard against liquidation From b2700f3151822ddcf06d276ad6c01f450cea34ae Mon Sep 17 00:00:00 2001 From: Peter Bushnell Date: Sat, 8 Oct 2022 11:59:27 +0100 Subject: [PATCH 06/11] Track loan differences in live economy --- src/masternodes/govvariables/attributes.cpp | 14 ++++ src/masternodes/govvariables/attributes.h | 4 ++ src/masternodes/loan.cpp | 12 ---- src/masternodes/loan.h | 10 --- src/masternodes/mn_checks.cpp | 12 ++-- src/masternodes/rpc_loan.cpp | 78 --------------------- src/validation.cpp | 35 ++++++--- 7 files changed, 48 insertions(+), 117 deletions(-) diff --git a/src/masternodes/govvariables/attributes.cpp b/src/masternodes/govvariables/attributes.cpp index c2503d0367a..3c8b1324967 100644 --- a/src/masternodes/govvariables/attributes.cpp +++ b/src/masternodes/govvariables/attributes.cpp @@ -209,6 +209,7 @@ const std::map>& ATTRIBUTES::displayKeys { AttributeTypes::Live, { {EconomyKeys::PaybackDFITokens, "dfi_payback_tokens"}, + {EconomyKeys::PaybackDFINoInterest,"dfi_payback_no_interest"}, {EconomyKeys::DFIP2203Current, "dfip2203_current"}, {EconomyKeys::DFIP2203Burned, "dfip2203_burned"}, {EconomyKeys::DFIP2203Minted, "dfip2203_minted"}, @@ -218,6 +219,8 @@ const std::map>& ATTRIBUTES::displayKeys {EconomyKeys::DFIP2206FMinted, "dfip2206f_minted"}, {EconomyKeys::NegativeInt, "negative_interest"}, {EconomyKeys::NegativeIntCurrent, "negative_interest_current"}, + {EconomyKeys::BatchRounding, "batch_rounding"}, + {EconomyKeys::AuctionInterest, "auction_interest"}, } }, }; @@ -425,6 +428,17 @@ void TrackNegativeInterest(CCustomCSView& mnview, const CTokenAmount& amount) { mnview.SetVariable(*attributes); } +void TrackLiveBalances(CCustomCSView& mnview, const CBalances& balances, const uint8_t key) { + auto attributes = mnview.GetAttributes(); + assert(attributes); + const CDataStructureV0 liveKey{AttributeTypes::Live, ParamIDs::Economy, key}; + auto storedBalances = attributes->GetValue(liveKey, CBalances{}); + for (const auto& [tokenID, amount] : balances.balances) { + storedBalances.balances[tokenID] += amount; + } + attributes->SetValue(liveKey, storedBalances); +} + Res ATTRIBUTES::ProcessVariable(const std::string& key, const std::string& value, std::function applyVariable) { diff --git a/src/masternodes/govvariables/attributes.h b/src/masternodes/govvariables/attributes.h index 2ac5abbc752..22cec12419c 100644 --- a/src/masternodes/govvariables/attributes.h +++ b/src/masternodes/govvariables/attributes.h @@ -48,6 +48,9 @@ enum EconomyKeys : uint8_t { DexTokens = 'i', NegativeInt = 'j', NegativeIntCurrent = 'k', + BatchRounding = 'l', // Extra added to loan amounts on auction creation due to round errors. + AuctionInterest = 'm', // Amount added to loan amounts after auction with no bids. + PaybackDFINoInterest = 'n', // Same as PaybackDFITokens but without interest. }; enum DFIPKeys : uint8_t { @@ -196,6 +199,7 @@ using CAttributeType = std::variant; using CAttributeValue = std::variant; void TrackNegativeInterest(CCustomCSView& mnview, const CTokenAmount& amount); +void TrackLiveBalances(CCustomCSView& mnview, const CBalances& balances, const uint8_t key); enum GovVarsFilter { All, diff --git a/src/masternodes/loan.cpp b/src/masternodes/loan.cpp index b82a9e32b78..1737be7c1fc 100644 --- a/src/masternodes/loan.cpp +++ b/src/masternodes/loan.cpp @@ -301,18 +301,6 @@ void CLoanView::WriteInterestRate(const std::pair& pair, const } } -std::map CLoanView::GetExcessLoans() const { - std::map excessLoans; - if (Read(ExcessLoanTokens::prefix(), excessLoans)) { - return excessLoans; - } - return {}; -} - -bool CLoanView::SetExcessLoans(const std::map& excessLoans) { - return Write(ExcessLoanTokens::prefix(), excessLoans); -} - Res CLoanView::IncreaseInterest(const uint32_t height, const CVaultId& vaultId, const std::string& loanSchemeID, const DCT_ID id, const CAmount tokenInterest, const CAmount loanIncreased) { const auto scheme = GetLoanScheme(loanSchemeID); diff --git a/src/masternodes/loan.h b/src/masternodes/loan.h index 2535e171bdb..a19b70f0877 100644 --- a/src/masternodes/loan.h +++ b/src/masternodes/loan.h @@ -480,18 +480,9 @@ class CLoanView : public virtual CStorageView { Res SetLoanLiquidationPenalty(CAmount penalty); CAmount GetLoanLiquidationPenalty(); - [[nodiscard]] std::map GetExcessLoans() const; - bool SetExcessLoans(const std::map& excessLoans); - [[nodiscard]] virtual std::optional GetLoanTokenFromAttributes(const DCT_ID& id) const = 0; [[nodiscard]] virtual std::optional GetCollateralTokenFromAttributes(const DCT_ID& id) const = 0; - enum ExcessLoanType : uint8_t { - BatchRounding, - AuctionInterest, - DFIPayback, - }; - struct LoanSetCollateralTokenCreationTx { static constexpr uint8_t prefix() { return 0x10; } }; struct LoanSetCollateralTokenKey { static constexpr uint8_t prefix() { return 0x11; } }; struct LoanSetLoanTokenCreationTx { static constexpr uint8_t prefix() { return 0x12; } }; @@ -505,7 +496,6 @@ class CLoanView : public virtual CStorageView { struct LoanLiquidationPenalty { static constexpr uint8_t prefix() { return 0x1A; } }; struct LoanInterestV2ByVault { static constexpr uint8_t prefix() { return 0x1B; } }; struct LoanInterestV3ByVault { static constexpr uint8_t prefix() { return 0x1C; } }; - struct ExcessLoanTokens { static constexpr uint8_t prefix() { return 0x1D; } }; }; #endif // DEFI_MASTERNODES_LOAN_H diff --git a/src/masternodes/mn_checks.cpp b/src/masternodes/mn_checks.cpp index df2916e5a3b..9c86d4db3db 100644 --- a/src/masternodes/mn_checks.cpp +++ b/src/masternodes/mn_checks.cpp @@ -3606,13 +3606,13 @@ class CCustomTxApplyVisitor : public CCustomTxVisitor { CDataStructureV0 liveKey{AttributeTypes::Live, ParamIDs::Economy, EconomyKeys::PaybackDFITokens}; auto balances = attributes->GetValue(liveKey, CBalances{}); + balances.Add({loanTokenId, subAmount}); + balances.Add({paybackTokenId, penalty}); + attributes->SetValue(liveKey, balances); - auto excessLoans = mnview.GetExcessLoans(); - excessLoans[static_cast(CLoanView::ExcessLoanType::DFIPayback)].Add({loanTokenId, subLoan}); - mnview.SetExcessLoans(excessLoans); - - balances.Add(CTokenAmount{loanTokenId, subAmount}); - balances.Add(CTokenAmount{paybackTokenId, penalty}); + liveKey.key = EconomyKeys::PaybackDFINoInterest; + balances = attributes->GetValue(liveKey, CBalances{}); + balances.Add({loanTokenId, subLoan}); attributes->SetValue(liveKey, balances); LogPrint(BCLog::LOAN, "CLoanPaybackLoanMessage(): Burning interest and loan in %s directly - total loan %lld (%lld %s), height - %d\n", paybackToken->symbol, subLoan + subInterest, subInToken, paybackToken->symbol, height); diff --git a/src/masternodes/rpc_loan.cpp b/src/masternodes/rpc_loan.cpp index db3b7538f60..11e5a091839 100644 --- a/src/masternodes/rpc_loan.cpp +++ b/src/masternodes/rpc_loan.cpp @@ -4,8 +4,6 @@ extern UniValue tokenToJSON(CCustomCSView& view, DCT_ID const& id, CTokenImplementation const& token, bool verbose); extern std::pair GetFixedIntervalPriceBlocks(int currentHeight, const CCustomCSView &mnview); -extern UniValue AmountsToJSON(TAmounts const & diffs, AmountFormat format = AmountFormat::Symbol); -extern std::string tokenAmountString(CTokenAmount const& amount, AmountFormat format = AmountFormat::Symbol); UniValue setCollateralTokenToJSON(CCustomCSView& view, CLoanSetCollateralTokenImplementation const& collToken) { @@ -1619,81 +1617,6 @@ UniValue paybackwithcollateral(const JSONRPCRequest& request) { return signsend(rawTx, pwallet, optAuthTx)->GetHash().GetHex(); } -UniValue loanamountdifferences(const JSONRPCRequest& request) { - auto pwallet = GetWallet(request); - - RPCHelpMan{"loanamountdifferences", - "Returns the differences between token minted and total loan amounts in vaults\n", - {}, - RPCResult{ - "{...} (object) JSON object with loan token information\n" - }, - RPCExamples{ - HelpExampleCli("loanamountdifferences", "") + - HelpExampleRpc("loanamountdifferences", "") - }, - }.Check(request); - - if (auto res = GetRPCResultCache().TryGet(request)) return *res; - - LOCK(cs_main); - - const auto excessLoans = pcustomcsview->GetExcessLoans(); - - UniValue ret(UniValue::VARR); - - for (const auto& [key, balances] : excessLoans) { - UniValue retObj(UniValue::VOBJ); - switch(key) { - case CLoanView::ExcessLoanType::BatchRounding: { - UniValue obj(UniValue::VARR); - for (auto const &[tokenId, amount]: balances.balances) { - obj.push_back(tokenAmountString({tokenId, -amount})); - } - retObj.pushKV("BatchRounding", obj); - break; - } - case CLoanView::ExcessLoanType::AuctionInterest: { - UniValue obj(UniValue::VARR); - for (auto const &[tokenId, amount]: balances.balances) { - obj.push_back(tokenAmountString({tokenId, -amount})); - } - retObj.pushKV("AuctionInterest", obj); - break; - } - case CLoanView::ExcessLoanType::DFIPayback: { - UniValue obj(UniValue::VARR); - for (auto const &[tokenId, amount]: balances.balances) { - obj.push_back(tokenAmountString({tokenId, -amount})); - } - retObj.pushKV("DFIPayback", obj); - break; - } - } - ret.push_back(retObj); - } - - const CDataStructureV0 mintedKey{AttributeTypes::Live, ParamIDs::Economy, EconomyKeys::DFIP2203Minted}; - const CDataStructureV0 negativeInterestKey{AttributeTypes::Live, ParamIDs::Economy, EconomyKeys::NegativeInt}; - const auto attributes = pcustomcsview->GetAttributes(); - const auto minted = attributes->GetValue(mintedKey, CBalances{}); - const auto negativeBalances = attributes->GetValue(negativeInterestKey, CBalances{}); - - { - UniValue retObj(UniValue::VOBJ); - retObj.pushKV("Futures", AmountsToJSON(minted.balances)); - ret.push_back(retObj); - } - - { - UniValue retObj(UniValue::VOBJ); - retObj.pushKV("NegativeInterest", AmountsToJSON(negativeBalances.balances)); - ret.push_back(retObj); - } - - return GetRPCResultCache().Set(request, ret); -} - static const CRPCCommand commands[] = { // category name actor (function) params @@ -1716,7 +1639,6 @@ static const CRPCCommand commands[] = {"vault", "paybackwithcollateral", &paybackwithcollateral, {"vaultId"}}, {"loan", "getloaninfo", &getloaninfo, {}}, {"loan", "getinterest", &getinterest, {"id", "token"}}, - {"loan", "loanamountdifferences", &loanamountdifferences, {}}, }; void RegisterLoanRPCCommands(CRPCTable& tableRPC) { diff --git a/src/validation.cpp b/src/validation.cpp index 9fc1f804050..58d26c37ea8 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -2511,19 +2511,24 @@ bool CChainState::ConnectBlock(const CBlock& block, CValidationState& state, CBl return true; }, pindex->nHeight); - auto excessLoans = mnview.GetExcessLoans(); - const CDataStructureV0 mintedKey{AttributeTypes::Live, ParamIDs::Economy, EconomyKeys::DFIP2203Minted}; const CDataStructureV0 negativeInterestKey{AttributeTypes::Live, ParamIDs::Economy, EconomyKeys::NegativeInt}; + const CDataStructureV0 batchRoundingKey{AttributeTypes::Live, ParamIDs::Economy, EconomyKeys::BatchRounding}; + const CDataStructureV0 auctionInterestKey{AttributeTypes::Live, ParamIDs::Economy, EconomyKeys::AuctionInterest}; + const CDataStructureV0 dfiPaybackKey{AttributeTypes::Live, ParamIDs::Economy, EconomyKeys::PaybackDFINoInterest}; + const auto attributes = mnview.GetAttributes(); auto minted = attributes->GetValue(mintedKey, CBalances{}); auto negativeBalances = attributes->GetValue(negativeInterestKey, CBalances{}); + auto batchRoundingBalances = attributes->GetValue(batchRoundingKey, CBalances{}); + auto auctionInterestBalances = attributes->GetValue(auctionInterestKey, CBalances{}); + auto dfiPaybackBalances = attributes->GetValue(dfiPaybackKey, CBalances{}); const auto totalDUSD = loanDUSD + auctionDUSD - - excessLoans[CLoanView::ExcessLoanType::BatchRounding].balances[token->first] - - excessLoans[CLoanView::ExcessLoanType::AuctionInterest].balances[token->first] - + excessLoans[CLoanView::ExcessLoanType::DFIPayback].balances[token->first] + - batchRoundingBalances.balances[token->first] + - auctionInterestBalances.balances[token->first] + + dfiPaybackBalances.balances[token->first] + minted.balances[token->first] + negativeBalances.balances[token->first]; @@ -3464,17 +3469,21 @@ void CChainState::ProcessLoanEvents(const CBlockIndex* pindex, CCustomCSView& ca } // Check if more than loan amount was generated. + CBalances balances; for (const auto& [tokenId, amount] : loanTokens->balances) { if (totalLoanInBatches.balances.count(tokenId)) { const auto interest = totalInterest.balances.count(tokenId) ? totalInterest.balances[tokenId] : 0; if (totalLoanInBatches.balances[tokenId] > amount - interest) { - auto excessLoans = cache.GetExcessLoans(); - excessLoans[static_cast(CLoanView::ExcessLoanType::BatchRounding)].Add({tokenId, totalLoanInBatches.balances[tokenId] - (amount - interest)}); - cache.SetExcessLoans(excessLoans); + balances.Add({tokenId, totalLoanInBatches.balances[tokenId] - (amount - interest)}); } } } + // Only store to attributes if there has been a rounding error. + if (!balances.balances.empty()) { + TrackLiveBalances(cache, balances, EconomyKeys::BatchRounding); + } + // All done. Ready to save the overall auction. cache.StoreAuction(vaultId, CAuctionData{ uint32_t(batches.size()), @@ -3501,6 +3510,7 @@ void CChainState::ProcessLoanEvents(const CBlockIndex* pindex, CCustomCSView& ca auto vault = view.GetVault(vaultId); assert(vault); + CBalances balances; for (uint32_t i = 0; i < data.batchCount; i++) { auto batch = view.GetAuctionBatch({vaultId, i}); assert(batch); @@ -3558,9 +3568,7 @@ void CChainState::ProcessLoanEvents(const CBlockIndex* pindex, CCustomCSView& ca } else { // we should return loan including interest view.AddLoanToken(vaultId, batch->loanAmount); - auto excessLoans = cache.GetExcessLoans(); - excessLoans[static_cast(CLoanView::ExcessLoanType::AuctionInterest)].Add({batch->loanAmount.nTokenId, batch->loanInterest}); - cache.SetExcessLoans(excessLoans); + balances.Add({batch->loanAmount.nTokenId, batch->loanInterest}); if (auto token = view.GetLoanTokenByID(batch->loanAmount.nTokenId)) { view.IncreaseInterest(pindex->nHeight, vaultId, vault->schemeId, batch->loanAmount.nTokenId, token->interest, batch->loanAmount.nValue); } @@ -3572,6 +3580,11 @@ void CChainState::ProcessLoanEvents(const CBlockIndex* pindex, CCustomCSView& ca } } + // Only store to attributes if there has been a rounding error. + if (!balances.balances.empty()) { + TrackLiveBalances(view, balances, EconomyKeys::AuctionInterest); + } + vault->isUnderLiquidation = false; view.StoreVault(vaultId, *vault); view.EraseAuction(vaultId, pindex->nHeight); From f4ab1679370bacb9c8bc2cddb9a1ea905611448d Mon Sep 17 00:00:00 2001 From: Peter Bushnell Date: Sat, 8 Oct 2022 12:25:19 +0100 Subject: [PATCH 07/11] Update attributes --- src/masternodes/govvariables/attributes.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/masternodes/govvariables/attributes.cpp b/src/masternodes/govvariables/attributes.cpp index 3c8b1324967..4bd3d59da78 100644 --- a/src/masternodes/govvariables/attributes.cpp +++ b/src/masternodes/govvariables/attributes.cpp @@ -437,6 +437,7 @@ void TrackLiveBalances(CCustomCSView& mnview, const CBalances& balances, const u storedBalances.balances[tokenID] += amount; } attributes->SetValue(liveKey, storedBalances); + mnview.SetVariable(*attributes); } Res ATTRIBUTES::ProcessVariable(const std::string& key, const std::string& value, From b64fbcd177c596c9a9ef11a0db54aaef72e19fdb Mon Sep 17 00:00:00 2001 From: Peter Bushnell Date: Sat, 8 Oct 2022 12:41:48 +0100 Subject: [PATCH 08/11] Migrate balances on split --- src/validation.cpp | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/validation.cpp b/src/validation.cpp index 58d26c37ea8..b6814f4f6df 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -4729,6 +4729,21 @@ static Res VaultSplits(CCustomCSView& view, ATTRIBUTES& attributes, const DCT_ID return Res::Ok(); } +static void MigrateV1Remnants(const CCustomCSView &cache, ATTRIBUTES &attributes, uint8_t key, DCT_ID oldId, DCT_ID newId, int32_t multiplier) { + CDataStructureV0 attrKey{AttributeTypes::Live, ParamIDs::Economy, key}; + auto balances = attributes.GetValue(attrKey, CBalances{}); + for (auto it = balances.balances.begin(); it != balances.balances.end(); ++it) { + const auto& [tokenId, amount] = *it; + if (tokenId != oldId) { + continue; + } + balances.balances.erase(it); + balances.Add({newId, CalculateNewAmount(multiplier, amount)}); + break; + } + attributes.SetValue(attrKey, balances); +} + void CChainState::ProcessTokenSplits(const CBlock& block, const CBlockIndex* pindex, CCustomCSView& cache, const CreationTxs& creationTxs, const CChainParams& chainparams) { if (pindex->nHeight < chainparams.GetConsensus().FortCanningCrunchHeight) { return; @@ -4843,6 +4858,9 @@ void CChainState::ProcessTokenSplits(const CBlock& block, const CBlockIndex* pin CDataStructureV0 descendantKey{AttributeTypes::Token, oldTokenId.v, TokenKeys::Descendant}; attributes->SetValue(descendantKey, DescendantValue{newTokenId.v, static_cast(pindex->nHeight)}); + MigrateV1Remnants(cache, *attributes, EconomyKeys::BatchRounding, oldTokenId, newTokenId, multiplier); + MigrateV1Remnants(cache, *attributes, EconomyKeys::AuctionInterest, oldTokenId, newTokenId, multiplier); + CAmount totalBalance{0}; res = PoolSplits(view, totalBalance, *attributes, oldTokenId, newTokenId, pindex, creationTxs, multiplier); From ec9ed1980d94b110b481715c77151aa0e3656db4 Mon Sep 17 00:00:00 2001 From: Peter Bushnell Date: Mon, 10 Oct 2022 07:26:48 +0100 Subject: [PATCH 09/11] Remove minted balance checking --- src/validation.cpp | 54 ---------------------------------------------- 1 file changed, 54 deletions(-) diff --git a/src/validation.cpp b/src/validation.cpp index b6814f4f6df..f2029c671ca 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -2491,60 +2491,6 @@ bool CChainState::ConnectBlock(const CBlock& block, CValidationState& state, CBl assert(*pindex->phashBlock == block.GetHash()); int64_t nTimeStart = GetTimeMicros(); - if (const auto token = mnview.GetToken("DUSD")) { - CAmount loanDUSD{}, auctionDUSD{}; - mnview.ForEachLoanTokenAmount([&](const CVaultId& vaultId, const CBalances& balances){ - for (const auto& [tokenId, amount] : balances.balances) { - if (tokenId == token->first) { - loanDUSD += amount; - } - } - return true; - }); - - mnview.ForEachVaultAuction([&](const CVaultId& vaultId, const CAuctionData& data) { - for (uint32_t i = 0; i < data.batchCount; ++i) { - if (const auto batch = mnview.GetAuctionBatch({vaultId, i}); batch && batch->loanAmount.nTokenId == token->first) { - auctionDUSD += batch->loanAmount.nValue - batch->loanInterest; - } - } - return true; - }, pindex->nHeight); - - const CDataStructureV0 mintedKey{AttributeTypes::Live, ParamIDs::Economy, EconomyKeys::DFIP2203Minted}; - const CDataStructureV0 negativeInterestKey{AttributeTypes::Live, ParamIDs::Economy, EconomyKeys::NegativeInt}; - const CDataStructureV0 batchRoundingKey{AttributeTypes::Live, ParamIDs::Economy, EconomyKeys::BatchRounding}; - const CDataStructureV0 auctionInterestKey{AttributeTypes::Live, ParamIDs::Economy, EconomyKeys::AuctionInterest}; - const CDataStructureV0 dfiPaybackKey{AttributeTypes::Live, ParamIDs::Economy, EconomyKeys::PaybackDFINoInterest}; - - const auto attributes = mnview.GetAttributes(); - auto minted = attributes->GetValue(mintedKey, CBalances{}); - auto negativeBalances = attributes->GetValue(negativeInterestKey, CBalances{}); - auto batchRoundingBalances = attributes->GetValue(batchRoundingKey, CBalances{}); - auto auctionInterestBalances = attributes->GetValue(auctionInterestKey, CBalances{}); - auto dfiPaybackBalances = attributes->GetValue(dfiPaybackKey, CBalances{}); - - const auto totalDUSD = loanDUSD - + auctionDUSD - - batchRoundingBalances.balances[token->first] - - auctionInterestBalances.balances[token->first] - + dfiPaybackBalances.balances[token->first] - + minted.balances[token->first] - + negativeBalances.balances[token->first]; - - if (token->second->minted != totalDUSD) { - return state.Invalid( - ValidationInvalidReason::CONSENSUS, - error("%s: Block height %d mismatch DUSD minted %s DUSD loan amount %s", - __func__, - pindex->nHeight, - GetDecimaleString(token->second->minted), - GetDecimaleString(totalDUSD)), - REJECT_INVALID, - "token-balance-mismatch"); - } - } - // Interrupt on hash or height requested. Invalidate the block. if (StopOrInterruptConnect(pindex, state)) return false; From 7371de432dd9fd3befcccc25ec5c85cdd62adb76 Mon Sep 17 00:00:00 2001 From: Peter Bushnell Date: Wed, 9 Nov 2022 07:28:46 +0000 Subject: [PATCH 10/11] tests: fix failure --- test/functional/feature_loan_vault.py | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/test/functional/feature_loan_vault.py b/test/functional/feature_loan_vault.py index cb353f6297d..8271a318909 100755 --- a/test/functional/feature_loan_vault.py +++ b/test/functional/feature_loan_vault.py @@ -25,7 +25,7 @@ def set_test_params(self): self.owner_addresses = [] self.oracles = [] - def move_to_gw_fork(self): + def move_to_fork(self): result = self.nodes[0].listcollateraltokens() assert_equal(result[0]['token'], 'DFI') assert_equal(result[0]['factor'], Decimal('1.00000000')) @@ -736,14 +736,7 @@ def overflowed_collateral_value(self): def loan_and_collateral_token_to_govvar(self): # Move to hard fork - self.move_to_gw_fork() - - # Invalidate fork block - self.nodes[0].invalidateblock(self.nodes[0].getblockhash(self.nodes[0].getblockcount())) - assert_equal(len(self.nodes[0].getgov('ATTRIBUTES')['ATTRIBUTES']), 0) - - # Move to hard fork again - self.move_to_gw_fork() + self.move_to_fork() # Test setting collateral token partially self.nodes[0].setgov({"ATTRIBUTES":{f'v0/token/{self.idETH}/fixed_interval_price_id':'ETH/USD', f'v0/token/{self.idETH}/loan_collateral_enabled':'true'}}) From 2f00752efac0e76897a32bca3c60ced9f293094f Mon Sep 17 00:00:00 2001 From: Peter Bushnell Date: Fri, 11 Nov 2022 16:04:47 +0000 Subject: [PATCH 11/11] Change keys for live stats --- src/masternodes/govvariables/attributes.cpp | 9 +++++---- src/masternodes/govvariables/attributes.h | 7 ++++--- src/masternodes/mn_checks.cpp | 2 +- src/validation.cpp | 12 ++++++------ 4 files changed, 16 insertions(+), 14 deletions(-) diff --git a/src/masternodes/govvariables/attributes.cpp b/src/masternodes/govvariables/attributes.cpp index c8e766c421f..74a1413fb28 100644 --- a/src/masternodes/govvariables/attributes.cpp +++ b/src/masternodes/govvariables/attributes.cpp @@ -105,6 +105,7 @@ const std::map& ATTRIBUTES::displayParamsIDs() { {ParamIDs::TokenID, "token"}, {ParamIDs::Economy, "economy"}, {ParamIDs::Feature, "feature"}, + {ParamIDs::Auction, "auction"}, }; return params; } @@ -221,7 +222,7 @@ const std::map>& ATTRIBUTES::displayKeys { AttributeTypes::Live, { {EconomyKeys::PaybackDFITokens, "dfi_payback_tokens"}, - {EconomyKeys::PaybackDFINoInterest,"dfi_payback_no_interest"}, + {EconomyKeys::PaybackDFITokensPrincipal,"dfi_payback_tokens_principal"}, {EconomyKeys::DFIP2203Current, "dfip2203_current"}, {EconomyKeys::DFIP2203Burned, "dfip2203_burned"}, {EconomyKeys::DFIP2203Minted, "dfip2203_minted"}, @@ -231,8 +232,8 @@ const std::map>& ATTRIBUTES::displayKeys {EconomyKeys::DFIP2206FMinted, "dfip2206f_minted"}, {EconomyKeys::NegativeInt, "negative_interest"}, {EconomyKeys::NegativeIntCurrent, "negative_interest_current"}, - {EconomyKeys::BatchRounding, "batch_rounding"}, - {EconomyKeys::AuctionInterest, "auction_interest"}, + {EconomyKeys::BatchRoundingExcess, "batch_rounding_excess"}, + {EconomyKeys::ConsolidatedInterest, "consolidated_interest"}, } }, }; @@ -448,7 +449,7 @@ void TrackNegativeInterest(CCustomCSView& mnview, const CTokenAmount& amount) { void TrackLiveBalances(CCustomCSView& mnview, const CBalances& balances, const uint8_t key) { auto attributes = mnview.GetAttributes(); assert(attributes); - const CDataStructureV0 liveKey{AttributeTypes::Live, ParamIDs::Economy, key}; + const CDataStructureV0 liveKey{AttributeTypes::Live, ParamIDs::Auction, key}; auto storedBalances = attributes->GetValue(liveKey, CBalances{}); for (const auto& [tokenID, amount] : balances.balances) { storedBalances.balances[tokenID] += amount; diff --git a/src/masternodes/govvariables/attributes.h b/src/masternodes/govvariables/attributes.h index 86a45643350..7886609fd87 100644 --- a/src/masternodes/govvariables/attributes.h +++ b/src/masternodes/govvariables/attributes.h @@ -31,6 +31,7 @@ enum ParamIDs : uint8_t { DFIP2206A = 'f', DFIP2206F = 'g', Feature = 'h', + Auction = 'i', }; enum OracleIDs : uint8_t { @@ -49,9 +50,9 @@ enum EconomyKeys : uint8_t { DexTokens = 'i', NegativeInt = 'j', NegativeIntCurrent = 'k', - BatchRounding = 'l', // Extra added to loan amounts on auction creation due to round errors. - AuctionInterest = 'm', // Amount added to loan amounts after auction with no bids. - PaybackDFINoInterest = 'n', // Same as PaybackDFITokens but without interest. + BatchRoundingExcess = 'l', // Extra added to loan amounts on auction creation due to round errors. + ConsolidatedInterest = 'm', // Amount added to loan amounts after auction with no bids. + PaybackDFITokensPrincipal = 'n', // Same as PaybackDFITokens but without interest. }; enum DFIPKeys : uint8_t { diff --git a/src/masternodes/mn_checks.cpp b/src/masternodes/mn_checks.cpp index 8dcd5d8df23..61e3abb6a4b 100644 --- a/src/masternodes/mn_checks.cpp +++ b/src/masternodes/mn_checks.cpp @@ -3651,7 +3651,7 @@ class CCustomTxApplyVisitor : public CCustomTxVisitor balances.Add({paybackTokenId, penalty}); attributes->SetValue(liveKey, balances); - liveKey.key = EconomyKeys::PaybackDFINoInterest; + liveKey.key = EconomyKeys::PaybackDFITokensPrincipal; balances = attributes->GetValue(liveKey, CBalances{}); balances.Add({loanTokenId, subLoan}); attributes->SetValue(liveKey, balances); diff --git a/src/validation.cpp b/src/validation.cpp index f2029c671ca..7d856aab86c 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -3427,7 +3427,7 @@ void CChainState::ProcessLoanEvents(const CBlockIndex* pindex, CCustomCSView& ca // Only store to attributes if there has been a rounding error. if (!balances.balances.empty()) { - TrackLiveBalances(cache, balances, EconomyKeys::BatchRounding); + TrackLiveBalances(cache, balances, EconomyKeys::BatchRoundingExcess); } // All done. Ready to save the overall auction. @@ -3528,7 +3528,7 @@ void CChainState::ProcessLoanEvents(const CBlockIndex* pindex, CCustomCSView& ca // Only store to attributes if there has been a rounding error. if (!balances.balances.empty()) { - TrackLiveBalances(view, balances, EconomyKeys::AuctionInterest); + TrackLiveBalances(view, balances, EconomyKeys::ConsolidatedInterest); } vault->isUnderLiquidation = false; @@ -4675,8 +4675,8 @@ static Res VaultSplits(CCustomCSView& view, ATTRIBUTES& attributes, const DCT_ID return Res::Ok(); } -static void MigrateV1Remnants(const CCustomCSView &cache, ATTRIBUTES &attributes, uint8_t key, DCT_ID oldId, DCT_ID newId, int32_t multiplier) { - CDataStructureV0 attrKey{AttributeTypes::Live, ParamIDs::Economy, key}; +static void MigrateV1Remnants(const CCustomCSView &cache, ATTRIBUTES &attributes, const uint8_t key, const DCT_ID oldId, const DCT_ID newId, const int32_t multiplier, const uint8_t typeID = ParamIDs::Economy) { + CDataStructureV0 attrKey{AttributeTypes::Live, typeID, key}; auto balances = attributes.GetValue(attrKey, CBalances{}); for (auto it = balances.balances.begin(); it != balances.balances.end(); ++it) { const auto& [tokenId, amount] = *it; @@ -4804,8 +4804,8 @@ void CChainState::ProcessTokenSplits(const CBlock& block, const CBlockIndex* pin CDataStructureV0 descendantKey{AttributeTypes::Token, oldTokenId.v, TokenKeys::Descendant}; attributes->SetValue(descendantKey, DescendantValue{newTokenId.v, static_cast(pindex->nHeight)}); - MigrateV1Remnants(cache, *attributes, EconomyKeys::BatchRounding, oldTokenId, newTokenId, multiplier); - MigrateV1Remnants(cache, *attributes, EconomyKeys::AuctionInterest, oldTokenId, newTokenId, multiplier); + MigrateV1Remnants(cache, *attributes, EconomyKeys::BatchRoundingExcess, oldTokenId, newTokenId, multiplier, ParamIDs::Auction); + MigrateV1Remnants(cache, *attributes, EconomyKeys::ConsolidatedInterest, oldTokenId, newTokenId, multiplier, ParamIDs::Auction); CAmount totalBalance{0};