diff --git a/src/arith_uint256.cpp b/src/arith_uint256.cpp index 901b82ddf2..b092977a4d 100644 --- a/src/arith_uint256.cpp +++ b/src/arith_uint256.cpp @@ -269,3 +269,25 @@ arith_uint256 UintToArith256(const uint256 &a) b.pn[x] = ReadLE32(a.begin() + x*4); return b; } + +base_uint<128> Arith256ToBaseUInt128(arith_uint256 const & b) +{ + base_uint<128> a; + + a |= ((b >> 64).GetLow64()); + a <<= 64; + a |= b.GetLow64(); + + return (a); +} + +arith_uint256 BaseUInt128ToArith256(base_uint<128> const & b) +{ + arith_uint256 a; + + a |= ((b >> 64).GetLow64()); + a <<= 64; + a |= b.GetLow64(); + + return (a); +} diff --git a/src/arith_uint256.h b/src/arith_uint256.h index 3934ca156c..bdcb0e43a9 100644 --- a/src/arith_uint256.h +++ b/src/arith_uint256.h @@ -297,5 +297,7 @@ class arith_uint256 : public base_uint<256> { uint256 ArithToUint256(const arith_uint256 &); arith_uint256 UintToArith256(const uint256 &); +base_uint<128> Arith256ToBaseUInt128(arith_uint256 const &); +arith_uint256 BaseUInt128ToArith256(base_uint<128> const &); #endif // DEFI_ARITH_UINT256_H diff --git a/src/masternodes/loan.cpp b/src/masternodes/loan.cpp index bd32cbb3fd..c8a003ee81 100644 --- a/src/masternodes/loan.cpp +++ b/src/masternodes/loan.cpp @@ -195,20 +195,14 @@ void CLoanView::EraseDelayedDestroyScheme(const std::string& loanSchemeID) EraseBy(loanSchemeID); } -boost::optional CLoanView::GetInterestRate(const CVaultId& vaultId, DCT_ID id) -{ - return ReadBy(std::make_pair(vaultId, id)); -} - -boost::optional CLoanView::GetInterestRateV2(const CVaultId& vaultId, DCT_ID id, uint32_t height) +boost::optional CLoanView::GetInterestRate(const CVaultId& vaultId, DCT_ID id, uint32_t height) { if (height >= Params().GetConsensus().FortCanningHillHeight) { - return ReadBy(std::make_pair(vaultId, id)); + return ReadBy(std::make_pair(vaultId, id)); } - if (auto rate = GetInterestRate(vaultId, id)) { + if (auto rate = ReadBy(std::make_pair(vaultId, id))) return ConvertInterestRateToV2(*rate); - } return {}; } @@ -222,12 +216,14 @@ inline T InterestPerBlockCalculationV1(CAmount amount, CAmount tokenInterest, CA return MultiplyAmounts(netInterest, amount) / blocksPerYear; } -// precisoin COIN ^2 +// precisoin COIN ^3 inline base_uint<128> InterestPerBlockCalculationV2(CAmount amount, CAmount tokenInterest, CAmount schemeInterest) { - auto netInterest = (tokenInterest + schemeInterest) / 100; // in % - static const base_uint<128> blocksPerYear = 365 * Params().GetConsensus().blocksPerDay(); - return base_uint<128>(netInterest) * base_uint<128>(amount) / blocksPerYear; + arith_uint256 netInterest = (tokenInterest + schemeInterest) / 100; // in % + static const arith_uint256 blocksPerYear = 365 * Params().GetConsensus().blocksPerDay(); + arith_uint256 result = netInterest * arith_uint256(amount) * arith_uint256(COIN) / blocksPerYear; + + return (Arith256ToBaseUInt128(result)); } static base_uint<128> InterestPerBlockCalculation(CAmount amount, CAmount tokenInterest, CAmount schemeInterest, uint32_t height) @@ -241,21 +237,22 @@ static base_uint<128> InterestPerBlockCalculation(CAmount amount, CAmount tokenI return InterestPerBlockCalculationV1(amount, tokenInterest, schemeInterest); } -static CAmount Ceil(const base_uint<128>& value, uint32_t height) +CAmount CeilInterest(const base_uint<128>& value, uint32_t height) { if (int(height) >= Params().GetConsensus().FortCanningHillHeight) { - CAmount amount = (value / base_uint<128>(COIN)).GetLow64(); - amount += CAmount(value != base_uint<128>(amount) * COIN); + CAmount amount = (value / base_uint<128>(HIGH_PRECISION_SCALER)).GetLow64(); + amount += CAmount(value != base_uint<128>(amount) * HIGH_PRECISION_SCALER); + return amount; } return value.GetLow64(); } -static base_uint<128> TotalInterestCalculation(const CInterestRateV2& rate, uint32_t height) +base_uint<128> TotalInterestCalculation(const CInterestRateV2& rate, uint32_t height) { auto interest = rate.interestToHeight + ((height - rate.height) * rate.interestPerBlock); - LogPrint(BCLog::LOAN, "%s(): CInterestRate{.height=%d, .perBlock=%d, .toHeight=%d}, height %d - totalInterest %d\n", __func__, rate.height, InterestPerBlock(rate, height), Ceil(rate.interestToHeight, height), height, Ceil(interest, height)); + LogPrint(BCLog::LOAN, "%s(): CInterestRate{.height=%d, .perBlock=%d, .toHeight=%d}, height %d - totalInterest %d\n", __func__, rate.height, InterestPerBlock(rate, height), CeilInterest(rate.interestToHeight, height), height, CeilInterest(interest, height)); return interest; } @@ -263,25 +260,25 @@ static base_uint<128> ToHigherPrecision(CAmount amount, uint32_t height) { base_uint<128> amountHP = amount; if (int(height) >= Params().GetConsensus().FortCanningHillHeight) { - amountHP *= COIN; + amountHP *= HIGH_PRECISION_SCALER; } return amountHP; } CAmount TotalInterest(const CInterestRateV2& rate, uint32_t height) { - return Ceil(TotalInterestCalculation(rate, height), height); + return CeilInterest(TotalInterestCalculation(rate, height), height); } CAmount InterestPerBlock(const CInterestRateV2& rate, uint32_t height) { - return Ceil(rate.interestPerBlock, height); + return CeilInterest(rate.interestPerBlock, height); } void CLoanView::WriteInterestRate(const std::pair& pair, const CInterestRateV2& rate, uint32_t height) { if (height >= Params().GetConsensus().FortCanningHillHeight) { - WriteBy(pair, rate); + WriteBy(pair, rate); } else { WriteBy(pair, ConvertInterestRateToV1(rate)); } @@ -299,7 +296,7 @@ Res CLoanView::StoreInterest(uint32_t height, const CVaultId& vaultId, const std } CInterestRateV2 rate{}; - if (auto readRate = GetInterestRateV2(vaultId, id, height)) + if (auto readRate = GetInterestRate(vaultId, id, height)) rate = *readRate; if (rate.height > height || height == 0) { @@ -309,7 +306,16 @@ Res CLoanView::StoreInterest(uint32_t height, const CVaultId& vaultId, const std LogPrint(BCLog::LOAN,"%s():\n", __func__); rate.interestToHeight = TotalInterestCalculation(rate, height); } - rate.interestPerBlock += InterestPerBlockCalculation(loanIncreased, token->interest, scheme->rate, height); + if (int(height) >= Params().GetConsensus().FortCanningHillHeight) + { + CBalances amounts; + if (!ReadBy(vaultId, amounts)) + return Res::Err("Cannot find current loan amount balance"); + + rate.interestPerBlock = InterestPerBlockCalculation(amounts.balances[id], token->interest, scheme->rate, height); + } + else + rate.interestPerBlock += InterestPerBlockCalculation(loanIncreased, token->interest, scheme->rate, height); rate.height = height; WriteInterestRate(std::make_pair(vaultId, id), rate, height); @@ -328,7 +334,7 @@ Res CLoanView::EraseInterest(uint32_t height, const CVaultId& vaultId, const std } CInterestRateV2 rate{}; - if (auto readRate = GetInterestRateV2(vaultId, id, height)) + if (auto readRate = GetInterestRate(vaultId, id, height)) rate = *readRate; if (rate.height > height) { @@ -344,9 +350,20 @@ Res CLoanView::EraseInterest(uint32_t height, const CVaultId& vaultId, const std : interestToHeight - interestDecreasedHP; rate.height = height; - auto interestPerBlock = InterestPerBlockCalculation(loanDecreased, token->interest, scheme->rate, height); - rate.interestPerBlock = rate.interestPerBlock < interestPerBlock ? 0 + if (int(height) >= Params().GetConsensus().FortCanningHillHeight) + { + CBalances amounts; + if (!ReadBy(vaultId, amounts)) + return Res::Err("Cannot find current loan amount balance"); + + rate.interestPerBlock = InterestPerBlockCalculation(amounts.balances[id], token->interest, scheme->rate, height); + } + else + { + auto interestPerBlock = InterestPerBlockCalculation(loanDecreased, token->interest, scheme->rate, height); + rate.interestPerBlock = rate.interestPerBlock < interestPerBlock ? 0 : rate.interestPerBlock - interestPerBlock; + } WriteInterestRate(std::make_pair(vaultId, id), rate, height); return Res::Ok(); @@ -361,22 +378,36 @@ void CLoanView::ForEachVaultInterest(std::function callback, const CVaultId& vaultId, DCT_ID id) { - ForEach, CInterestRateV2>([&](const std::pair& pair, CInterestRateV2 rate) { + ForEach, CInterestRateV2>([&](const std::pair& pair, CInterestRateV2 rate) { return callback(pair.first, pair.second, rate); }, std::make_pair(vaultId, id)); } -Res CLoanView::DeleteInterest(const CVaultId& vaultId) +Res CLoanView::DeleteInterest(const CVaultId& vaultId, uint32_t height) { std::vector> keysToDelete; - auto it = LowerBound(std::make_pair(vaultId, DCT_ID{0})); - for (; it.Valid() && it.Key().first == vaultId; it.Next()) { - keysToDelete.push_back(it.Key()); + if (height >= Params().GetConsensus().FortCanningHillHeight) + { + auto it = LowerBound(std::make_pair(vaultId, DCT_ID{0})); + for (; it.Valid() && it.Key().first == vaultId; it.Next()) { + keysToDelete.push_back(it.Key()); + } + + for (const auto& key : keysToDelete) { + EraseBy(key); + } } + else + { + auto it = LowerBound(std::make_pair(vaultId, DCT_ID{0})); + for (; it.Valid() && it.Key().first == vaultId; it.Next()) { + keysToDelete.push_back(it.Key()); + } - for (const auto& key : keysToDelete) { - EraseBy(key); + for (const auto& key : keysToDelete) { + EraseBy(key); + } } return Res::Ok(); } @@ -385,9 +416,11 @@ void CLoanView::RevertInterestRateToV1() { std::vector, CInterestRateV2>> rates; ForEach, CInterestRateV2>([&](const std::pair& pair, CInterestRateV2 rate) { - rate.interestPerBlock /= base_uint<128>(COIN); - rate.interestToHeight /= base_uint<128>(COIN); + rate.interestPerBlock /= HIGH_PRECISION_SCALER; + rate.interestToHeight /= HIGH_PRECISION_SCALER; rates.emplace_back(pair, std::move(rate)); + EraseBy(pair); + return true; }); @@ -396,19 +429,26 @@ void CLoanView::RevertInterestRateToV1() } } -void CLoanView::MigrateInterestRateToV2() +void CLoanView::MigrateInterestRateToV2(CVaultView &view, uint32_t height) { std::vector, CInterestRate>> rates; - ForEach, CInterestRate>([&](const std::pair& pair, CInterestRate rate) { - rates.emplace_back(pair, std::move(rate)); + ForEach, CInterestRate>([&](const std::pair& id, CInterestRate rate) { + rates.emplace_back(id, std::move(rate)); return true; }); for (auto it = rates.begin(); it != rates.end(); it = rates.erase(it)) { + auto vaultId = it->first.first; + auto tokenId = it->first.second; auto newRate = ConvertInterestRateToV2(it->second); - newRate.interestPerBlock *= base_uint<128>(COIN); - newRate.interestToHeight *= base_uint<128>(COIN); - WriteBy(it->first, newRate); + + newRate.interestPerBlock *= HIGH_PRECISION_SCALER; + newRate.interestToHeight *= HIGH_PRECISION_SCALER; + WriteBy(it->first, newRate); + + const auto vault = view.GetVault(vaultId); + auto loanToken = this->GetLoanTokenByID(tokenId); + StoreInterest(height, vaultId, vault->schemeId, tokenId, 0); } } diff --git a/src/masternodes/loan.h b/src/masternodes/loan.h index 9149a0a8b2..33cb7cfdb8 100644 --- a/src/masternodes/loan.h +++ b/src/masternodes/loan.h @@ -259,8 +259,12 @@ inline CInterestRateV2 ConvertInterestRateToV2(const CInterestRate& rate1) return rate2; } +static const CAmount HIGH_PRECISION_SCALER = COIN * COIN; // 1,0000,0000,0000,0000 + CAmount TotalInterest(const CInterestRateV2& rate, uint32_t height); CAmount InterestPerBlock(const CInterestRateV2& rate, uint32_t height); +base_uint<128> TotalInterestCalculation(const CInterestRateV2& rate, uint32_t height); +CAmount CeilInterest(const base_uint<128>& value, uint32_t height); class CLoanTakeLoanMessage { @@ -327,16 +331,15 @@ class CLoanView : public virtual CStorageView { void ForEachDelayedLoanScheme(std::function&, const CLoanSchemeMessage&)> callback); void ForEachDelayedDestroyScheme(std::function callback); - Res DeleteInterest(const CVaultId& vaultId); - boost::optional GetInterestRate(const CVaultId& loanSchemeID, DCT_ID id); - boost::optional GetInterestRateV2(const CVaultId& loanSchemeID, DCT_ID id, uint32_t height); + Res DeleteInterest(const CVaultId& vaultId, uint32_t height); + boost::optional GetInterestRate(const CVaultId& loanSchemeID, DCT_ID id, uint32_t height); void WriteInterestRate(const std::pair& pair, const CInterestRateV2& rate, uint32_t height); Res StoreInterest(uint32_t height, const CVaultId& vaultId, const std::string& loanSchemeID, DCT_ID id, CAmount loanIncreased); Res EraseInterest(uint32_t height, const CVaultId& vaultId, const std::string& loanSchemeID, DCT_ID id, CAmount loanDecreased, CAmount interestDecreased); void ForEachVaultInterest(std::function callback, const CVaultId& vaultId = uint256(), DCT_ID id = {0}); void ForEachVaultInterestV2(std::function callback, const CVaultId& vaultId = uint256(), DCT_ID id = {0}); void RevertInterestRateToV1(); - void MigrateInterestRateToV2(); + void MigrateInterestRateToV2(CVaultView &view, uint32_t height); Res AddLoanToken(const CVaultId& vaultId, CTokenAmount amount); Res SubLoanToken(const CVaultId& vaultId, CTokenAmount amount); @@ -357,6 +360,7 @@ class CLoanView : public virtual CStorageView { struct LoanInterestByVault { static constexpr uint8_t prefix() { return 0x18; } }; struct LoanTokenAmount { static constexpr uint8_t prefix() { return 0x19; } }; struct LoanLiquidationPenalty { static constexpr uint8_t prefix() { return 0x1A; } }; + struct LoanInterestV2ByVault { static constexpr uint8_t prefix() { return 0x1B; } }; }; #endif // DEFI_MASTERNODES_LOAN_H diff --git a/src/masternodes/masternodes.cpp b/src/masternodes/masternodes.cpp index 8c9dfbed16..86b528af9c 100644 --- a/src/masternodes/masternodes.cpp +++ b/src/masternodes/masternodes.cpp @@ -993,7 +993,7 @@ Res CCustomCSView::PopulateLoansData(CCollateralLoans& result, CVaultId const& v if (!token) return Res::Err("Loan token with id (%s) does not exist!", loanTokenId.ToString()); - auto rate = GetInterestRateV2(vaultId, loanTokenId, height); + auto rate = GetInterestRate(vaultId, loanTokenId, height); if (!rate) return Res::Err("Cannot get interest rate for token (%s)!", token->symbol); diff --git a/src/masternodes/masternodes.h b/src/masternodes/masternodes.h index 50623bc3f0..1df8259182 100644 --- a/src/masternodes/masternodes.h +++ b/src/masternodes/masternodes.h @@ -380,7 +380,7 @@ class CCustomCSView ICXOrderStatus, ICXOfferStatus, ICXSubmitDFCHTLCStatus, ICXSubmitEXTHTLCStatus, ICXVariables, CLoanView :: LoanSetCollateralTokenCreationTx, LoanSetCollateralTokenKey, LoanSetLoanTokenCreationTx, LoanSetLoanTokenKey, LoanSchemeKey, DefaultLoanSchemeKey, DelayedLoanSchemeKey, - DestroyLoanSchemeKey, LoanInterestByVault, LoanTokenAmount, LoanLiquidationPenalty, + DestroyLoanSchemeKey, LoanInterestByVault, LoanTokenAmount, LoanLiquidationPenalty, LoanInterestV2ByVault, CVaultView :: VaultKey, OwnerVaultKey, CollateralKey, AuctionBatchKey, AuctionHeightKey, AuctionBidKey >(); } diff --git a/src/masternodes/mn_checks.cpp b/src/masternodes/mn_checks.cpp index 95d56a56f3..97cfcf1ee5 100644 --- a/src/masternodes/mn_checks.cpp +++ b/src/masternodes/mn_checks.cpp @@ -2388,7 +2388,7 @@ class CCustomTxApplyVisitor : public CCustomTxVisitor } // delete all interest to vault - res = mnview.DeleteInterest(obj.vaultId); + res = mnview.DeleteInterest(obj.vaultId, height); if (!res) return res; @@ -2685,7 +2685,7 @@ class CCustomTxApplyVisitor : public CCustomTxVisitor if (it == loanAmounts->balances.end()) return Res::Err("There is no loan on token (%s) in this vault!", loanToken->symbol); - auto rate = mnview.GetInterestRateV2(obj.vaultId, tokenId, height); + auto rate = mnview.GetInterestRate(obj.vaultId, tokenId, height); if (!rate) return Res::Err("Cannot get interest rate for this token (%s)!", loanToken->symbol); @@ -2713,7 +2713,7 @@ class CCustomTxApplyVisitor : public CCustomTxVisitor if (static_cast(height) >= consensus.FortCanningMuseumHeight && static_cast(height) < consensus.FortCanningHillHeight && subLoan < it->second) { - auto newRate = mnview.GetInterestRateV2(obj.vaultId, tokenId, height); + auto newRate = mnview.GetInterestRate(obj.vaultId, tokenId, height); if (!newRate) return Res::Err("Cannot get interest rate for this token (%s)!", loanToken->symbol); @@ -3192,7 +3192,7 @@ void PopulateVaultHistoryData(CHistoryWriters* writers, CAccountsHistoryWriter& bool IsDisabledTx(uint32_t height, CustomTxType type, const Consensus::Params& consensus) { if (height < consensus.FortCanningParkHeight) return false; - + // ICXCreateOrder = '1', // ICXMakeOffer = '2', // ICXSubmitDFCHTLC = '3', @@ -3224,7 +3224,7 @@ Res ApplyCustomTx(CCustomCSView& mnview, const CCoinsViewCache& coins, const CTr const auto metadataValidation = height >= consensus.FortCanningHeight; - + auto txType = GuessCustomTxType(tx, metadata, metadataValidation); if (txType == CustomTxType::None) { return res; @@ -3233,7 +3233,7 @@ Res ApplyCustomTx(CCustomCSView& mnview, const CCoinsViewCache& coins, const CTr if (IsDisabledTx(height, txType, consensus)) { return Res::ErrCode(CustomTxErrCodes::Fatal, "Disabled custom transaction"); } - + if (metadataValidation && txType == CustomTxType::Reject) { return Res::ErrCode(CustomTxErrCodes::Fatal, "Invalid custom transaction"); } @@ -3549,7 +3549,7 @@ std::vector> CPoolSwap::CalculatePoolPaths(CCustomCSView& vi // Note: `testOnly` doesn't update views, and as such can result in a previous price calculations // for a pool, if used multiple times (or duplicated pool IDs) with the same view. -// testOnly is only meant for one-off tests per well defined view. +// testOnly is only meant for one-off tests per well defined view. Res CPoolSwap::ExecuteSwap(CCustomCSView& view, std::vector poolIDs, bool testOnly) { CTokenAmount swapAmountResult{{},0}; @@ -3619,7 +3619,7 @@ Res CPoolSwap::ExecuteSwap(CCustomCSView& view, std::vector poolIDs, boo // If we're just testing, don't do any balance transfers. // Just go over pools and return result. The only way this can - // cause inaccurate result is if we go over the same path twice, + // cause inaccurate result is if we go over the same path twice, // which shouldn't happen in the first place. if (testOnly) return Res::Ok(); diff --git a/src/masternodes/rpc_loan.cpp b/src/masternodes/rpc_loan.cpp index dbecd650db..061f86a683 100644 --- a/src/masternodes/rpc_loan.cpp +++ b/src/masternodes/rpc_loan.cpp @@ -1365,7 +1365,7 @@ UniValue getinterest(const JSONRPCRequest& request) { RPCCheckFortCanningHillConstraint(height); - std::map > interest; + std::map, base_uint<128>> > interest; LogPrint(BCLog::LOAN,"%s():\n", __func__); auto vaultInterest = [&](const CVaultId& vaultId, DCT_ID tokenId, CInterestRateV2 rate) @@ -1381,8 +1381,8 @@ UniValue getinterest(const JSONRPCRequest& request) { return true; LogPrint(BCLog::LOAN,"\t\tVault(%s)->", vaultId.GetHex()); /* Continued */ - interest[tokenId].first += TotalInterest(rate, height); - interest[tokenId].second += InterestPerBlock(rate, height); + interest[tokenId].first += TotalInterestCalculation(rate, height); + interest[tokenId].second += rate.interestPerBlock; return true; }; @@ -1396,12 +1396,17 @@ UniValue getinterest(const JSONRPCRequest& request) { } UniValue obj(UniValue::VOBJ); - for (std::map >::iterator it=interest.begin(); it!=interest.end(); ++it) + for (std::map, base_uint<128> > >::iterator it=interest.begin(); it!=interest.end(); ++it) { auto token = pcustomcsview->GetToken(it->first); obj.pushKV("token", token->CreateSymbolKey(it->first)); - obj.pushKV("totalInterest", ValueFromAmount(it->second.first)); - obj.pushKV("interestPerBlock", ValueFromAmount(it->second.second)); + obj.pushKV("totalInterest", ValueFromAmount(CeilInterest(it->second.first, height))); + obj.pushKV("interestPerBlock", ValueFromAmount(CeilInterest(it->second.second, height))); + if (height >= Params().GetConsensus().FortCanningHillHeight) + { + auto subSatoshiInterest = (it->second.second - ((it->second.second / HIGH_PRECISION_SCALER) * HIGH_PRECISION_SCALER)).GetLow64(); + obj.pushKV("immatureInterest", UniValue(UniValue::VNUM, strprintf("0.%d", subSatoshiInterest))); + } ret.push_back(obj); } diff --git a/src/masternodes/rpc_vault.cpp b/src/masternodes/rpc_vault.cpp index 60b175a35f..4554a710cd 100644 --- a/src/masternodes/rpc_vault.cpp +++ b/src/masternodes/rpc_vault.cpp @@ -154,7 +154,7 @@ namespace { for (const auto& loan : loanTokens->balances) { auto token = pcustomcsview->GetLoanTokenByID(loan.first); if (!token) continue; - auto rate = pcustomcsview->GetInterestRateV2(vaultId, loan.first, height); + auto rate = pcustomcsview->GetInterestRate(vaultId, loan.first, height); if (!rate) continue; LogPrint(BCLog::LOAN,"%s()->%s->", __func__, token->symbol); /* Continued */ auto totalInterest = TotalInterest(*rate, height + 1); diff --git a/src/test/loan_tests.cpp b/src/test/loan_tests.cpp index 56c150ff56..2bd1581ee6 100644 --- a/src/test/loan_tests.cpp +++ b/src/test/loan_tests.cpp @@ -81,42 +81,42 @@ BOOST_AUTO_TEST_CASE(loan_iterest_rate) const std::string id("sch1"); CreateScheme(mnview, id, 150, 2 * COIN); - // const CAmount tokenInterest = 5 * COIN; - // auto token_id = CreateLoanToken(mnview, "TST", "TEST", "", tokenInterest); - // auto scheme = mnview.GetLoanScheme(id); - // BOOST_REQUIRE(scheme); - // BOOST_CHECK_EQUAL(scheme->ratio, 150); - // BOOST_CHECK_EQUAL(scheme->rate, 2 * COIN); - - // auto vault_id = NextTx(); - // BOOST_REQUIRE(mnview.StoreInterest(1, vault_id, id, token_id, 1 * COIN)); - - // auto rate = mnview.GetInterestRate(vault_id, token_id); - // BOOST_REQUIRE(rate); - // BOOST_CHECK_EQUAL(rate->interestToHeight, 0); - // BOOST_CHECK_EQUAL(rate->height, 1); - - // auto interestPerBlock = rate->interestPerBlock; - // BOOST_REQUIRE(mnview.StoreInterest(5, vault_id, id, token_id, 1 * COIN)); - - // rate = mnview.GetInterestRate(vault_id, token_id); - // BOOST_REQUIRE(rate); - // BOOST_CHECK_EQUAL(rate->height, 5); - // BOOST_CHECK_EQUAL(rate->interestToHeight, 4 * interestPerBlock); - - // auto interestToHeight = rate->interestToHeight; - // interestPerBlock = rate->interestPerBlock; - // BOOST_REQUIRE(mnview.EraseInterest(6, vault_id, id, token_id, 1 * COIN, interestToHeight + interestPerBlock)); - // rate = mnview.GetInterestRate(vault_id, token_id); - - // BOOST_REQUIRE(rate); - // BOOST_CHECK_EQUAL(rate->interestToHeight, 0); - - // BOOST_REQUIRE(mnview.EraseInterest(6, vault_id, id, token_id, 1 * COIN, 0)); - - // rate = mnview.GetInterestRate(vault_id, token_id); - // BOOST_REQUIRE(rate); - // BOOST_CHECK_EQUAL(rate->interestToHeight, 0); + const CAmount tokenInterest = 5 * COIN; + auto token_id = CreateLoanToken(mnview, "TST", "TEST", "", tokenInterest); + auto scheme = mnview.GetLoanScheme(id); + BOOST_REQUIRE(scheme); + BOOST_CHECK_EQUAL(scheme->ratio, 150); + BOOST_CHECK_EQUAL(scheme->rate, 2 * COIN); + + auto vault_id = NextTx(); + BOOST_REQUIRE(mnview.StoreInterest(1, vault_id, id, token_id, 1 * COIN)); + + auto rate = mnview.GetInterestRate(vault_id, token_id, 1); + BOOST_REQUIRE(rate); + BOOST_CHECK_EQUAL(rate->interestToHeight.GetLow64(), 0); + BOOST_CHECK_EQUAL(rate->height, 1); + + auto interestPerBlock = rate->interestPerBlock; + BOOST_REQUIRE(mnview.StoreInterest(5, vault_id, id, token_id, 1 * COIN)); + + rate = mnview.GetInterestRate(vault_id, token_id, 5); + BOOST_REQUIRE(rate); + BOOST_CHECK_EQUAL(rate->height, 5); + BOOST_CHECK_EQUAL(rate->interestToHeight.GetLow64(), 4 * interestPerBlock.GetLow64()); + + auto interestToHeight = rate->interestToHeight; + interestPerBlock = rate->interestPerBlock; + BOOST_REQUIRE(mnview.EraseInterest(6, vault_id, id, token_id, 1 * COIN, (interestToHeight + interestPerBlock).GetLow64())); + rate = mnview.GetInterestRate(vault_id, token_id, 6); + + BOOST_REQUIRE(rate); + BOOST_CHECK_EQUAL(rate->interestToHeight.GetLow64(), 0); + + BOOST_REQUIRE(mnview.EraseInterest(6, vault_id, id, token_id, 1 * COIN, 0)); + + rate = mnview.GetInterestRate(vault_id, token_id, 6); + BOOST_REQUIRE(rate); + BOOST_CHECK_EQUAL(rate->interestToHeight.GetLow64(), 0); } BOOST_AUTO_TEST_CASE(collateralization_ratio) diff --git a/src/validation.cpp b/src/validation.cpp index 6ac0970eae..3c520c33ce 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -2320,7 +2320,7 @@ bool CChainState::ConnectBlock(const CBlock& block, CValidationState& state, CBl if (pindex->nHeight == chainparams.GetConsensus().FortCanningHillHeight) { auto time = GetTimeMillis(); LogPrintf("Interest rate migration ...\n"); - mnview.MigrateInterestRateToV2(); + mnview.MigrateInterestRateToV2(mnview,(uint32_t)pindex->nHeight); LogPrint(BCLog::BENCH, " - Interest rate migration took: %dms\n", GetTimeMillis() - time); } @@ -3131,7 +3131,7 @@ void CChainState::ProcessLoanEvents(const CBlockIndex* pindex, CCustomCSView& ca for (auto& loan : loanTokens->balances) { auto tokenId = loan.first; auto tokenValue = loan.second; - auto rate = cache.GetInterestRateV2(vaultId, tokenId, pindex->nHeight); + auto rate = cache.GetInterestRate(vaultId, tokenId, pindex->nHeight); assert(rate); LogPrint(BCLog::LOAN,"\t\t"); /* Continued */ auto subInterest = TotalInterest(*rate, pindex->nHeight);