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

Update DFI DUSD vault collateral requirement rules #1450

Merged
merged 41 commits into from
Sep 12, 2022
Merged
Show file tree
Hide file tree
Changes from 28 commits
Commits
Show all changes
41 commits
Select commit Hold shift + click to select a range
21ae678
Add Fort Canning Epilogue and prevent DUSD loop loans
prasannavl Sep 7, 2022
afd2ce5
Add tests, block height args
prasannavl Sep 7, 2022
77a5137
Update tests
prasannavl Sep 7, 2022
f3267cb
Add missing forks in tests
prasannavl Sep 7, 2022
6c04bed
Cleanup tests
prasannavl Sep 7, 2022
08c0de7
Minor formatting
prasannavl Sep 7, 2022
a6405a4
Better error message
prasannavl Sep 7, 2022
f28c53d
Add Collateral Check
prasannavl Sep 7, 2022
1ca565a
Add missing token check
prasannavl Sep 7, 2022
acef77c
Add const
prasannavl Sep 7, 2022
43d4922
Simplify for just collateral check
prasannavl Sep 7, 2022
a9c9247
Refactor DUSD usage checks
prasannavl Sep 7, 2022
0de7328
Additional refactors
prasannavl Sep 7, 2022
b0202a8
Add more tests
prasannavl Sep 7, 2022
13ec661
Add collateral check tests
prasannavl Sep 7, 2022
89f1c3d
Withdraw implementation after FCE
dcorral Sep 7, 2022
2569449
Merge branch 'master' of github.com:DeFiCh/ain into pvl/fce-no-dusd-loop
dcorral Sep 8, 2022
982c660
Fix merge leftover
dcorral Sep 8, 2022
b1b234b
Fix lint errors
dcorral Sep 8, 2022
3d2077e
Add rollback_to function to test framework
dcorral Sep 4, 2022
5f05245
Fix lint
dcorral Sep 4, 2022
cd078a0
Fix lint
dcorral Sep 4, 2022
5b3c0cf
clean up code
mambisi Sep 8, 2022
4aad566
add `feature_dusd_loans.py` to `test_runner.py`
mambisi Sep 8, 2022
7572955
Add FortCanningEpilogue fork
Bushstar Sep 7, 2022
b1fa9ca
Remove unused function
dcorral Sep 9, 2022
1df4fa0
Merge branch 'master' into pvl/fce-no-dusd-loop
dcorral Sep 9, 2022
11f7a4c
Fix percentage checks
dcorral Sep 9, 2022
8b0b897
better variable naming
mambisi Sep 9, 2022
a17154e
Merge branch 'master' of github.com:DeFiCh/ain into pvl/fce-no-dusd-loop
dcorral Sep 9, 2022
2c4e552
Fix lint errors
dcorral Sep 10, 2022
e04e8a6
Fix merge conflict leftover
dcorral Sep 10, 2022
15fcf36
Fix lint
dcorral Sep 10, 2022
bdd5867
remove unnecessary include on mn_checks
dcorral Sep 10, 2022
83b0d2a
Fix post FCR DFI percentage check
dcorral Sep 10, 2022
5a56351
Merge branch 'master' into pvl/fce-no-dusd-loop
dcorral Sep 10, 2022
77137b5
Add withdraw tests
dcorral Sep 10, 2022
d96e220
Merge branch 'pvl/fce-no-dusd-loop' of github.com:DeFiCh/ain into pvl…
dcorral Sep 10, 2022
9b8e431
Fix check of DUSD collateral token existance
dcorral Sep 10, 2022
143de79
Merge branch 'master' into pvl/fce-no-dusd-loop
prasannavl Sep 11, 2022
54b08fc
Merge branch 'master' into pvl/fce-no-dusd-loop
prasannavl Sep 12, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
131 changes: 89 additions & 42 deletions src/masternodes/mn_checks.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// Distributed under the MIT software license, see the accompanying
// file LICENSE or http://www.opensource.org/licenses/mit-license.php.

#include "amount.h"
#include <masternodes/accountshistory.h>
#include <masternodes/anchors.h>
#include <masternodes/balances.h>
Expand All @@ -26,6 +27,9 @@

#include <algorithm>

constexpr std::string_view ERR_STRING_MIN_COLLATERAL_DFI_PCT = "At least 50%% of the minimum required collateral must be in DFI";
constexpr std::string_view ERR_STRING_MIN_COLLATERAL_DFI_DUSD_PCT = "At least 50%% of the minimum required collateral must be in DFI or DUSD";

std::string ToString(CustomTxType type) {
switch (type)
{
Expand Down Expand Up @@ -2943,6 +2947,59 @@ class CCustomTxApplyVisitor : public CCustomTxVisitor
return mnview.UpdateVault(obj.vaultId, *vault);
}

Res CollateralPctCheck(const bool hasDUSDLoans, const CCollateralLoans& collateralsLoans, const uint32_t ratio) const {

std::optional<std::pair<DCT_ID, std::optional<CTokensView::CTokenImpl>>> tokenDUSD;
if (static_cast<int>(height) >= consensus.FortCanningRoadHeight) {
tokenDUSD = mnview.GetToken("DUSD");
}

// Calculate DFI and DUSD value separately
uint64_t totalCollateralsDUSD = 0;
uint64_t totalCollateralsDFI = 0;

for (auto& col : collateralsLoans.collaterals){
if (col.nTokenId == DCT_ID{0} )
totalCollateralsDFI += col.nValue;

if(tokenDUSD && col.nTokenId == tokenDUSD->first)
totalCollateralsDUSD += col.nValue;
}
auto totalCollaterals = totalCollateralsDUSD + totalCollateralsDFI;

// Heigh checks
auto isPostFCH = static_cast<int>(height) >= consensus.FortCanningHillHeight;
auto isPreFCH = static_cast<int>(height) < consensus.FortCanningHillHeight;
auto isPostFCE = static_cast<int>(height) >= consensus.FortCanningEpilogueHeight;
auto isPostFCR = static_cast<int>(height) >= consensus.FortCanningRoadHeight;

// Condition checks
auto isDFIHalfOfAllCollaterall = totalCollateralsDFI < collateralsLoans.totalCollaterals / 2;
auto isDFIAndDUSDHalfOfRequiredCollateral = arith_uint256(totalCollaterals)*100 < (arith_uint256(collateralsLoans.totalLoans) * ratio / 2);
auto isDFIHalfOfRequiredCollateral = arith_uint256(totalCollateralsDFI)*100 < (arith_uint256(collateralsLoans.totalLoans) * ratio / 2);
mambisi marked this conversation as resolved.
Show resolved Hide resolved

if(isPostFCE){
if (hasDUSDLoans){
if(isDFIHalfOfRequiredCollateral)
return Res::Err(std::string(ERR_STRING_MIN_COLLATERAL_DFI_PCT));
}else {
if(isDFIAndDUSDHalfOfRequiredCollateral)
return Res::Err(std::string(ERR_STRING_MIN_COLLATERAL_DFI_DUSD_PCT));
}
return Res::Ok();
}

if (isPostFCR && isDFIAndDUSDHalfOfRequiredCollateral)
return Res::Err(std::string(ERR_STRING_MIN_COLLATERAL_DFI_DUSD_PCT));
if (isPostFCH && isDFIHalfOfRequiredCollateral)
return Res::Err(std::string(ERR_STRING_MIN_COLLATERAL_DFI_PCT));
if (isPreFCH && isDFIHalfOfAllCollaterall)
return Res::Err(std::string(ERR_STRING_MIN_COLLATERAL_DFI_PCT));

return Res::Ok();
}


Res operator()(const CDepositToVaultMessage& obj) const {
auto res = CheckCustomTx();
if (!res)
Expand Down Expand Up @@ -2976,15 +3033,12 @@ class CCustomTxApplyVisitor : public CCustomTxVisitor
return Res::Err("Insufficient funds: can't subtract balance of %s: %s\n", ScriptToString(obj.from), res.msg);

res = mnview.AddVaultCollateral(obj.vaultId, obj.amount);
if (!res)
return res;
if (!res) return res;

bool useNextPrice = false, requireLivePrice = false;
auto collaterals = mnview.GetVaultCollaterals(obj.vaultId);

auto collateralsLoans = mnview.GetLoanCollaterals(obj.vaultId, *collaterals, height, time, useNextPrice, requireLivePrice);
if (!collateralsLoans)
return std::move(collateralsLoans);

auto scheme = mnview.GetLoanScheme(vault->schemeId);
if (collateralsLoans.val->ratio() < scheme->ratio)
Expand Down Expand Up @@ -3018,10 +3072,22 @@ class CCustomTxApplyVisitor : public CCustomTxVisitor
if (!res)
return res;

auto hasDUSDLoans = false;

std::optional<std::pair<DCT_ID, std::optional<CTokensView::CTokenImpl>>> tokenDUSD;
if (static_cast<int>(height) >= consensus.FortCanningRoadHeight) {
tokenDUSD = mnview.GetToken("DUSD");
}

if (const auto loanAmounts = mnview.GetLoanTokens(obj.vaultId))
{
// Update negative interest in vault
for (const auto& [tokenId, currentLoanAmount] : loanAmounts->balances) {

if (tokenDUSD && tokenId == tokenDUSD->first) {
hasDUSDLoans = true;
}

const auto rate = mnview.GetInterestRate(obj.vaultId, tokenId, height);
assert(rate);

Expand All @@ -3039,14 +3105,12 @@ class CCustomTxApplyVisitor : public CCustomTxVisitor
}

mnview.ResetInterest(height, obj.vaultId, vault->schemeId, tokenId);

}

if (auto collaterals = mnview.GetVaultCollaterals(obj.vaultId))
{
std::optional<std::pair<DCT_ID, std::optional<CTokensView::CTokenImpl>>> tokenDUSD;
if (static_cast<int>(height) >= consensus.FortCanningRoadHeight) {
tokenDUSD = mnview.GetToken("DUSD");
}

const auto scheme = mnview.GetLoanScheme(vault->schemeId);
for (int i = 0; i < 2; i++) {
// check collaterals for active and next price
Expand All @@ -3059,21 +3123,9 @@ class CCustomTxApplyVisitor : public CCustomTxVisitor
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);

uint64_t totalCollaterals = 0;

for (auto& col : collateralsLoans.val->collaterals)
if (col.nTokenId == DCT_ID{0}
|| (tokenDUSD && col.nTokenId == tokenDUSD->first))
totalCollaterals += col.nValue;

if (static_cast<int>(height) < consensus.FortCanningHillHeight) {
if (totalCollaterals < collateralsLoans.val->totalCollaterals / 2)
return Res::Err("At least 50%% of the collateral must be in DFI");
} else {
if (arith_uint256(totalCollaterals) * 100 < arith_uint256(collateralsLoans.val->totalLoans) * scheme->ratio / 2)
return static_cast<int>(height) < consensus.FortCanningRoadHeight ? Res::Err("At least 50%% of the minimum required collateral must be in DFI")
: Res::Err("At least 50%% of the minimum required collateral must be in DFI or DUSD");
}
res = CollateralPctCheck(hasDUSDLoans, collateralsLoans, scheme->ratio);
if(!res)
return res;
}
} else {
return Res::Err("Cannot withdraw all collaterals as there are still active loans in this vault");
Expand Down Expand Up @@ -3108,6 +3160,13 @@ class CCustomTxApplyVisitor : public CCustomTxVisitor

const auto loanAmounts = mnview.GetLoanTokens(obj.vaultId);

auto hasDUSDLoans = false;

std::optional<std::pair<DCT_ID, std::optional<CTokensView::CTokenImpl>>> tokenDUSD;
if (static_cast<int>(height) >= consensus.FortCanningRoadHeight) {
tokenDUSD = mnview.GetToken("DUSD");
}

uint64_t totalLoansActivePrice = 0, totalLoansNextPrice = 0;
for (const auto& [tokenId, tokenAmount] : obj.amounts.balances)
{
Expand All @@ -3121,6 +3180,10 @@ class CCustomTxApplyVisitor : public CCustomTxVisitor
if (!loanToken->mintable)
return Res::Err("Loan cannot be taken on token with id (%s) as \"mintable\" is currently false",tokenId.ToString());

if (tokenDUSD && tokenId == tokenDUSD->first) {
hasDUSDLoans = true;
}

// Calculate interest
CAmount currentLoanAmount{};
bool resetInterestToHeight{};
Expand Down Expand Up @@ -3201,10 +3264,6 @@ class CCustomTxApplyVisitor : public CCustomTxVisitor
return res;
}

std::optional<std::pair<DCT_ID, std::optional<CTokensView::CTokenImpl>>> tokenDUSD;
if (static_cast<int>(height) >= consensus.FortCanningRoadHeight) {
tokenDUSD = mnview.GetToken("DUSD");
}
auto scheme = mnview.GetLoanScheme(vault->schemeId);
for (int i = 0; i < 2; i++) {
// check ratio against current and active price
Expand All @@ -3217,21 +3276,9 @@ class CCustomTxApplyVisitor : public CCustomTxVisitor
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);

uint64_t totalCollaterals = 0;

for (auto& col : collateralsLoans.val->collaterals)
if (col.nTokenId == DCT_ID{0}
|| (tokenDUSD && col.nTokenId == tokenDUSD->first))
totalCollaterals += col.nValue;

if (static_cast<int>(height) < consensus.FortCanningHillHeight) {
if (totalCollaterals < collateralsLoans.val->totalCollaterals / 2)
return Res::Err("At least 50%% of the collateral must be in DFI when taking a loan.");
} else {
if (arith_uint256(totalCollaterals) * 100 < arith_uint256(collateralsLoans.val->totalLoans) * scheme->ratio / 2)
return static_cast<int>(height) < consensus.FortCanningRoadHeight ? Res::Err("At least 50%% of the minimum required collateral must be in DFI when taking a loan.")
: Res::Err("At least 50%% of the minimum required collateral must be in DFI or DUSD when taking a loan.");
}
res = CollateralPctCheck(hasDUSDLoans, collateralsLoans, scheme->ratio);
if(!res)
return res;
}
return Res::Ok();
}
Expand Down
Loading