Skip to content

Commit

Permalink
Skip token locked check (DeFiCh#1552)
Browse files Browse the repository at this point in the history
* Add flag to skip token is locked check

Return informative collateralValue and loanValue even if token is locked
in vault

* Skip IPB when token is locked

* Fix typo

* Fix test

* Update token_lock test

* Add IPB=-1 and IPBValue=-1 on locked token fetch

* Revert "Update token_lock test"

This reverts commit 9e12889.

* Update token_lock test

Co-authored-by: Shoham Chakraborty <[email protected]>
Co-authored-by: Prasanna Loganathar <[email protected]>
  • Loading branch information
3 people authored Nov 11, 2022
1 parent b216b42 commit ae4b4b6
Show file tree
Hide file tree
Showing 7 changed files with 67 additions and 36 deletions.
24 changes: 13 additions & 11 deletions src/masternodes/masternodes.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -945,9 +945,9 @@ CAmount CCollateralLoans::precisionRatio() const
return ratio > maxRatio / precision ? -COIN : CAmount(ratio * precision);
}

ResVal<CAmount> CCustomCSView::GetAmountInCurrency(CAmount amount, CTokenCurrencyPair priceFeedId, bool useNextPrice, bool requireLivePrice)
ResVal<CAmount> CCustomCSView::GetAmountInCurrency(CAmount amount, CTokenCurrencyPair priceFeedId, bool useNextPrice, bool requireLivePrice, bool skipLockedCheck)
{
auto priceResult = GetValidatedIntervalPrice(priceFeedId, useNextPrice, requireLivePrice);
auto priceResult = GetValidatedIntervalPrice(priceFeedId, useNextPrice, requireLivePrice, skipLockedCheck);
if (!priceResult)
return priceResult;

Expand All @@ -960,18 +960,18 @@ ResVal<CAmount> CCustomCSView::GetAmountInCurrency(CAmount amount, CTokenCurrenc
}

ResVal<CCollateralLoans> CCustomCSView::GetLoanCollaterals(CVaultId const& vaultId, CBalances const& collaterals, uint32_t height,
int64_t blockTime, bool useNextPrice, bool requireLivePrice)
int64_t blockTime, bool useNextPrice, bool requireLivePrice, bool skipLockedCheck)
{
const auto vault = GetVault(vaultId);
if (!vault || vault->isUnderLiquidation)
return Res::Err("Vault is under liquidation");

CCollateralLoans result{};
auto res = PopulateLoansData(result, vaultId, height, blockTime, useNextPrice, requireLivePrice);
auto res = PopulateLoansData(result, vaultId, height, blockTime, useNextPrice, requireLivePrice, skipLockedCheck);
if (!res)
return std::move(res);

res = PopulateCollateralData(result, vaultId, collaterals, height, blockTime, useNextPrice, requireLivePrice);
res = PopulateCollateralData(result, vaultId, collaterals, height, blockTime, useNextPrice, requireLivePrice, skipLockedCheck);
if (!res)
return std::move(res);

Expand All @@ -981,12 +981,14 @@ ResVal<CCollateralLoans> CCustomCSView::GetLoanCollaterals(CVaultId const& vault
return {result, Res::Ok()};
}

ResVal<CAmount> CCustomCSView::GetValidatedIntervalPrice(const CTokenCurrencyPair& priceFeedId, bool useNextPrice, bool requireLivePrice)
ResVal<CAmount> CCustomCSView::GetValidatedIntervalPrice(const CTokenCurrencyPair& priceFeedId, bool useNextPrice, bool requireLivePrice, bool skipLockedCheck)
{
auto tokenSymbol = priceFeedId.first;
auto currency = priceFeedId.second;

auto priceFeed = GetFixedIntervalPrice(priceFeedId);
LogPrint(BCLog::ORACLE,"\t\t%s()->for_loans->%s->", __func__, tokenSymbol); /* Continued */

auto priceFeed = GetFixedIntervalPrice(priceFeedId, skipLockedCheck);
if (!priceFeed)
return std::move(priceFeed);

Expand All @@ -1002,7 +1004,7 @@ ResVal<CAmount> CCustomCSView::GetValidatedIntervalPrice(const CTokenCurrencyPai
}

Res CCustomCSView::PopulateLoansData(CCollateralLoans& result, CVaultId const& vaultId, uint32_t height,
int64_t blockTime, bool useNextPrice, bool requireLivePrice)
int64_t blockTime, bool useNextPrice, bool requireLivePrice, bool skipLockedCheck)
{
const auto loanTokens = GetLoanTokens(vaultId);
if (!loanTokens)
Expand All @@ -1025,7 +1027,7 @@ Res CCustomCSView::PopulateLoansData(CCollateralLoans& result, CVaultId const& v
if (totalAmount < 0) {
totalAmount = 0;
}
const auto amountInCurrency = GetAmountInCurrency(totalAmount, token->fixedIntervalPriceId, useNextPrice, requireLivePrice);
const auto amountInCurrency = GetAmountInCurrency(totalAmount, token->fixedIntervalPriceId, useNextPrice, requireLivePrice, skipLockedCheck);
if (!amountInCurrency)
return amountInCurrency;

Expand All @@ -1041,7 +1043,7 @@ Res CCustomCSView::PopulateLoansData(CCollateralLoans& result, CVaultId const& v
}

Res CCustomCSView::PopulateCollateralData(CCollateralLoans& result, CVaultId const& vaultId, CBalances const& collaterals,
uint32_t height, int64_t blockTime, bool useNextPrice, bool requireLivePrice)
uint32_t height, int64_t blockTime, bool useNextPrice, bool requireLivePrice, bool skipLockedCheck)
{
for (const auto& col : collaterals.balances) {
auto tokenId = col.first;
Expand All @@ -1051,7 +1053,7 @@ Res CCustomCSView::PopulateCollateralData(CCollateralLoans& result, CVaultId con
if (!token)
return Res::Err("Collateral token with id (%s) does not exist!", tokenId.ToString());

auto amountInCurrency = GetAmountInCurrency(tokenAmount, token->fixedIntervalPriceId, useNextPrice, requireLivePrice);
auto amountInCurrency = GetAmountInCurrency(tokenAmount, token->fixedIntervalPriceId, useNextPrice, requireLivePrice, skipLockedCheck);
if (!amountInCurrency)
return std::move(amountInCurrency);

Expand Down
10 changes: 5 additions & 5 deletions src/masternodes/masternodes.h
Original file line number Diff line number Diff line change
Expand Up @@ -403,8 +403,8 @@ class CCustomCSView
>();
}
private:
Res PopulateLoansData(CCollateralLoans& result, CVaultId const& vaultId, uint32_t height, int64_t blockTime, bool useNextPrice, bool requireLivePrice);
Res PopulateCollateralData(CCollateralLoans& result, CVaultId const& vaultId, CBalances const& collaterals, uint32_t height, int64_t blockTime, bool useNextPrice, bool requireLivePrice);
Res PopulateLoansData(CCollateralLoans& result, CVaultId const& vaultId, uint32_t height, int64_t blockTime, bool useNextPrice, bool requireLivePrice, bool skipLockedCheck);
Res PopulateCollateralData(CCollateralLoans& result, CVaultId const& vaultId, CBalances const& collaterals, uint32_t height, int64_t blockTime, bool useNextPrice, bool requireLivePrice, bool skipLockedCheck);

std::unique_ptr<CAccountHistoryStorage> accHistoryStore;
std::unique_ptr<CVaultHistoryStorage> vauHistoryStore;
Expand Down Expand Up @@ -436,11 +436,11 @@ class CCustomCSView

bool CalculateOwnerRewards(CScript const & owner, uint32_t height);

ResVal<CAmount> GetAmountInCurrency(CAmount amount, CTokenCurrencyPair priceFeedId, bool useNextPrice = false, bool requireLivePrice = true);
ResVal<CAmount> GetAmountInCurrency(CAmount amount, CTokenCurrencyPair priceFeedId, bool useNextPrice = false, bool requireLivePrice = true, bool skipLockedCheck = false);

ResVal<CCollateralLoans> GetLoanCollaterals(CVaultId const & vaultId, CBalances const & collaterals, uint32_t height, int64_t blockTime, bool useNextPrice = false, bool requireLivePrice = true);
ResVal<CCollateralLoans> GetLoanCollaterals(CVaultId const & vaultId, CBalances const & collaterals, uint32_t height, int64_t blockTime, bool useNextPrice = false, bool requireLivePrice = true, bool skipLockedCheck = false);

ResVal<CAmount> GetValidatedIntervalPrice(const CTokenCurrencyPair& priceFeedId, bool useNextPrice, bool requireLivePrice);
ResVal<CAmount> GetValidatedIntervalPrice(const CTokenCurrencyPair& priceFeedId, bool useNextPrice, bool requireLivePrice, bool skipLockedCheck = false);

[[nodiscard]] bool AreTokensLocked(const std::set<uint32_t>& tokenIds) const override;
[[nodiscard]] std::optional<CTokenImpl> GetTokenGuessId(const std::string & str, DCT_ID & id) const override;
Expand Down
4 changes: 2 additions & 2 deletions src/masternodes/oracles.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@ Res COracleView::SetFixedIntervalPrice(const CFixedIntervalPrice& fixedIntervalP
return Res::Ok();
}

ResVal<CFixedIntervalPrice> COracleView::GetFixedIntervalPrice(const CTokenCurrencyPair& fixedIntervalPriceId)
ResVal<CFixedIntervalPrice> COracleView::GetFixedIntervalPrice(const CTokenCurrencyPair& fixedIntervalPriceId, bool skipLockedCheck)
{
CFixedIntervalPrice fixedIntervalPrice;
if (!ReadBy<FixedIntervalPriceKey>(fixedIntervalPriceId, fixedIntervalPrice)) {
Expand All @@ -172,7 +172,7 @@ ResVal<CFixedIntervalPrice> COracleView::GetFixedIntervalPrice(const CTokenCurre
loanTokens.insert(secondID.v);
}

if (AreTokensLocked(loanTokens)) {
if (AreTokensLocked(loanTokens) && !skipLockedCheck) {
return Res::Err("Fixed interval price currently disabled due to locked token");
}

Expand Down
2 changes: 1 addition & 1 deletion src/masternodes/oracles.h
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,7 @@ class COracleView : public virtual CStorageView

Res SetFixedIntervalPrice(const CFixedIntervalPrice& PriceFeed);

ResVal<CFixedIntervalPrice> GetFixedIntervalPrice(const CTokenCurrencyPair& priceFeedId);
ResVal<CFixedIntervalPrice> GetFixedIntervalPrice(const CTokenCurrencyPair& priceFeedId, bool skipLockedCheck = false);

void ForEachFixedIntervalPrice(std::function<bool(const CTokenCurrencyPair&, CLazySerialize<CFixedIntervalPrice>)> callback, const CTokenCurrencyPair& start = {});

Expand Down
40 changes: 25 additions & 15 deletions src/masternodes/rpc_vault.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ namespace {
return auctionObj;
}

UniValue VaultToJSON(const CVaultId& vaultId, const CVaultData& vault, const bool verbose = false) {
UniValue VaultToJSON(const CVaultId& vaultId, const CVaultData& vault, const bool verbose = false, const bool skipLockedCheck = false) {
UniValue result{UniValue::VOBJ};
auto vaultState = GetVaultState(vaultId, vault);
auto height = ::ChainActive().Height();
Expand All @@ -132,11 +132,11 @@ namespace {
if (!collaterals)
collaterals = CBalances{};


auto blockTime = ::ChainActive().Tip()->GetBlockTime();
bool useNextPrice = false, requireLivePrice = vaultState != VaultState::Frozen;
LogPrint(BCLog::LOAN,"%s():\n", __func__);

if (auto rate = pcustomcsview->GetLoanCollaterals(vaultId, *collaterals, height + 1, blockTime, useNextPrice, requireLivePrice)) {
if (auto rate = pcustomcsview->GetLoanCollaterals(vaultId, *collaterals, height + 1, blockTime, useNextPrice, requireLivePrice, skipLockedCheck)) {
collValue = ValueFromUint(rate.val->totalCollaterals);
loanValue = ValueFromUint(rate.val->totalLoans);
ratioValue = ValueFromAmount(rate.val->precisionRatio());
Expand Down Expand Up @@ -172,7 +172,7 @@ namespace {
auto totalInterest = TotalInterest(*rate, height + 1);
auto value = amount + totalInterest;
if (value > 0) {
if (auto priceFeed = pcustomcsview->GetFixedIntervalPrice(token->fixedIntervalPriceId)) {
if (auto priceFeed = pcustomcsview->GetFixedIntervalPrice(token->fixedIntervalPriceId, skipLockedCheck)) {
auto price = priceFeed.val->priceRecord[0];
if (const auto interestCalculation = MultiplyAmounts(price, totalInterest)) {
totalInterests += interestCalculation;
Expand Down Expand Up @@ -211,7 +211,7 @@ namespace {
result.pushKV("collateralAmounts", AmountsToJSON(collaterals->balances));
result.pushKV("loanAmounts", loanBalances);
result.pushKV("interestAmounts", interestAmounts);
if (isVaultTokenLocked){
if (isVaultTokenLocked && !skipLockedCheck){
collValue = -1;
loanValue = -1;
interestValue = -1;
Expand All @@ -228,15 +228,13 @@ namespace {
result.pushKV("collateralRatio", collateralRatio);
if (verbose) {
useNextPrice = true;
if (auto rate = pcustomcsview->GetLoanCollaterals(vaultId, *collaterals, height + 1, blockTime, useNextPrice, requireLivePrice)) {
if (auto rate = pcustomcsview->GetLoanCollaterals(vaultId, *collaterals, height + 1, blockTime, useNextPrice, requireLivePrice, skipLockedCheck)) {
nextCollateralRatio = int(rate.val->ratio());
result.pushKV("nextCollateralRatio", nextCollateralRatio);
}
if (height >= Params().GetConsensus().FortCanningHillHeight) {
if(isVaultTokenLocked){
result.pushKV("interestPerBlockValue", -1);
} else {
result.pushKV("interestPerBlockValue", GetInterestPerBlockHighPrecisionString(interestsPerBlockValueHighPrecision));
if(!isVaultTokenLocked && skipLockedCheck) {
totalInterestsPerBlockValue = GetInterestPerBlockHighPrecisionString(interestsPerBlockValueHighPrecision);
for (const auto& [id, interestPerBlock] : interestsPerBlockHighPrecission) {
auto tokenId = id;
auto amountStr = GetInterestPerBlockHighPrecisionString(interestPerBlock);
Expand All @@ -249,9 +247,17 @@ namespace {
} else {
interestsPerBlockBalances = AmountsToJSON(interestsPerBlock);
totalInterestsPerBlockValue = ValueFromAmount(totalInterestsPerBlock);
}
if (!isVaultTokenLocked){
// IPB can only be calculated when tokens are not locked.
// Value during split period is hard to predict with the current|next price
result.pushKV("interestsPerBlock", interestsPerBlockBalances);
result.pushKV("interestPerBlockValue", totalInterestsPerBlockValue);
} else {
result.pushKV("interestsPerBlock", -1);
result.pushKV("interestPerBlockValue", -1);

}
result.pushKV("interestsPerBlock", interestsPerBlockBalances);
}
return result;
}
Expand Down Expand Up @@ -463,6 +469,10 @@ UniValue listvaults(const JSONRPCRequest& request) {
{
"verbose", RPCArg::Type::BOOL, RPCArg::Optional::OMITTED,
"Flag for verbose list (default = false), otherwise only ids, ownerAddress, loanSchemeIds and state are listed"
},
{
"skipLockedCheck", RPCArg::Type::BOOL, RPCArg::Optional::OMITTED,
"If true, return collateral and loan values even if token is locked"
}
},
},
Expand Down Expand Up @@ -508,6 +518,7 @@ UniValue listvaults(const JSONRPCRequest& request) {
std::string loanSchemeId;
VaultState state{VaultState::Unknown};
bool verbose{false};
bool skipPriceChecks{false};
if (request.params.size() > 0) {
UniValue optionsObj = request.params[0].get_obj();
if (!optionsObj["ownerAddress"].isNull()) {
Expand All @@ -519,9 +530,8 @@ UniValue listvaults(const JSONRPCRequest& request) {
if (!optionsObj["state"].isNull()) {
state = StringToVaultState(optionsObj["state"].getValStr());
}
if (!optionsObj["verbose"].isNull()) {
verbose = optionsObj["verbose"].getBool();
}
verbose = optionsObj["verbose"].getBool();
skipPriceChecks = optionsObj["skipLockedCheck"].getBool();
}

// parse pagination
Expand Down Expand Up @@ -571,7 +581,7 @@ UniValue listvaults(const JSONRPCRequest& request) {
vaultObj.pushKV("loanSchemeId", data.schemeId);
vaultObj.pushKV("state", VaultStateToString(vaultState));
} else {
vaultObj = VaultToJSON(vaultId, data);
vaultObj = VaultToJSON(vaultId, data, verbose, skipPriceChecks);
}
valueArr.push_back(vaultObj);
limit--;
Expand Down
2 changes: 1 addition & 1 deletion test/functional/feature_token_lock.py
Original file line number Diff line number Diff line change
Expand Up @@ -280,7 +280,7 @@ def vault_lock(self):
assert_equal(result['informativeRatio'], -1)
assert_equal(result['collateralRatio'], -1)
assert_equal(result['interestPerBlockValue'], -1)
assert_equal(result['interestsPerBlock'], [])
assert_equal(result['interestsPerBlock'], -1)

# Deposit to vault should fail
assert_raises_rpc_error(-32600, "Fixed interval price currently disabled due to locked token", self.nodes[0].deposittovault, self.vault, self.address, f'100000@{self.symbolDUSD}')
Expand Down
21 changes: 20 additions & 1 deletion test/functional/feature_token_split_usd_value.py
Original file line number Diff line number Diff line change
Expand Up @@ -310,19 +310,38 @@ def test_values_non_zero_with_token_locked(self):
assert_equal(vault["interestValue"], -1)
assert_equal(vault["informativeRatio"], -1)
assert_equal(vault["collateralRatio"], -1)
vaults_values = self.nodes[0].listvaults({"skipLockedCheck": False, "verbose": True})
for vault in vaults_values:
assert_equal(vault["state"], "frozen")
assert_equal(vault["collateralValue"], -1)
assert_equal(vault["loanValue"], -1)
assert_equal(vault["interestValue"], -1)
assert_equal(vault["informativeRatio"], -1)
assert_equal(vault["collateralRatio"], -1)
assert_equal(vault["interestsPerBlock"], -1)
assert_equal(vault["interestPerBlockValue"], -1)

vaults_values = self.nodes[0].listvaults({"skipLockedCheck": True, "verbose": True})
for vault in vaults_values:
assert_greater_than_or_equal(vault["collateralValue"], 0)
assert_greater_than_or_equal(vault["loanValue"], 0)
assert_equal(vault["interestsPerBlock"], -1)
assert_equal(vault["interestPerBlockValue"], -1)

def test_values_after_token_unlock(self):
# Unlock token
self.nodes[0].setgov({"ATTRIBUTES":{f'v0/locks/token/{self.idT1}':'false'}})
self.nodes[0].generate(1)
vaults_values = self.get_vaults_usd_values()
vaults_values = self.nodes[0].listvaults({"skipLockedCheck": True, "verbose": True})
for vault in vaults_values:
assert_equal(vault["state"], "active")
assert_greater_than_or_equal(vault["collateralValue"], 0)
assert_greater_than_or_equal(vault["loanValue"], 0)
assert_greater_than_or_equal(vault["interestValue"], 0)
assert_greater_than_or_equal(vault["informativeRatio"], 0)
assert_greater_than_or_equal(vault["collateralRatio"], 0)
assert_greater_than_or_equal(Decimal(vault["interestsPerBlock"][0].split('@')[0]), 0)
assert_greater_than_or_equal(Decimal(vault["interestPerBlockValue"]), 0)

def run_test(self):
self.setup()
Expand Down

0 comments on commit ae4b4b6

Please sign in to comment.