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 23 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
4 changes: 2 additions & 2 deletions src/chainparams.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@ class CMainParams : public CChainParams {
consensus.FortCanningCrunchHeight = 1936000; // June 2, 2022.
consensus.FortCanningSpringHeight = 2033000; // July 6, 2022.
consensus.FortCanningGreatWorldHeight = 2212000; // Sep 7th, 2022.
consensus.FortCanningEpilogueHeight = std::numeric_limits<int>::max();
consensus.FortCanningEpilogueHeight = 2218000;
dcorral marked this conversation as resolved.
Show resolved Hide resolved

consensus.pos.diffLimit = uint256S("00000fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff");
// consensus.pos.nTargetTimespan = 14 * 24 * 60 * 60; // two weeks
Expand Down Expand Up @@ -376,7 +376,7 @@ class CTestNetParams : public CChainParams {
consensus.FortCanningCrunchHeight = 1011600;
consensus.FortCanningSpringHeight = 1086000;
consensus.FortCanningGreatWorldHeight = 1223000;
consensus.FortCanningEpilogueHeight = std::numeric_limits<int>::max();
consensus.FortCanningEpilogueHeight = 1233000;

consensus.pos.diffLimit = uint256S("00000fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff");
// consensus.pos.nTargetTimespan = 14 * 24 * 60 * 60; // two weeks
Expand Down
2 changes: 1 addition & 1 deletion src/init.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -503,7 +503,7 @@ void SetupServerArgs()
gArgs.AddArg("-fortcanningspringheight", "Fort Canning Spring fork activation height (regtest only)", ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::CHAINPARAMS);
gArgs.AddArg("-fortcanninggreatworldheight", "Fort Canning Great World fork activation height (regtest only)", ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::CHAINPARAMS);
gArgs.AddArg("-greatworldheight", "Alias for Fort Canning Great World fork activation height (regtest only)", ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::CHAINPARAMS);
gArgs.AddArg("-fortcanningepilogueheight", "Alias for Fort Canning Epilogue fork activation height (regtest only)", ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::CHAINPARAMS);
gArgs.AddArg("-fortcanningepilogueheight", "Fort Canning Epilogue fork activation height (regtest only)", ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::CHAINPARAMS);
gArgs.AddArg("-jellyfish_regtest", "Configure the regtest network for jellyfish testing", ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::OPTIONS);
gArgs.AddArg("-simulatemainnet", "Configure the regtest network to mainnet target timespan and spacing ", ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::OPTIONS);
gArgs.AddArg("-dexstats", strprintf("Enable storing live dex data in DB (default: %u)", DEFAULT_DEXSTATS), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
Expand Down
127 changes: 95 additions & 32 deletions src/masternodes/mn_checks.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@

#include <algorithm>

constexpr std::string_view ERR_STRING_DUSD_USAGE = "DUSD can either be used as collateral or loaned, but not both at the same time after Fort Canning Epilogue";

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

Res CollateralAddVerifyDUSDUsage(DCT_ID collateralInToken, const CCollateralLoans& colleteralLoans) const {
if (static_cast<int>(height) < consensus.FortCanningEpilogueHeight)
return Res::Ok();

auto tokenDUSD = mnview.GetToken("DUSD");
if (!tokenDUSD)
return Res::Err("DUSD token not found");

if (collateralInToken != tokenDUSD->first)
return Res::Ok();

for (const auto& item : colleteralLoans.loans) {
if (item.nTokenId == tokenDUSD->first) {
return Res::Err(std::string(ERR_STRING_DUSD_USAGE));
}
}
return Res::Ok();
}

Res operator()(const CDepositToVaultMessage& obj) const {
auto res = CheckCustomTx();
if (!res)
Expand Down Expand Up @@ -2976,15 +2997,16 @@ 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);
if (!collateralsLoans) return std::move(collateralsLoans);

res = CollateralAddVerifyDUSDUsage(obj.amount.nTokenId, collateralsLoans);
dcorral marked this conversation as resolved.
Show resolved Hide resolved
if (!res) return res;

auto scheme = mnview.GetLoanScheme(vault->schemeId);
if (collateralsLoans.val->ratio() < scheme->ratio)
Expand Down Expand Up @@ -3018,10 +3040,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 +3073,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,17 +3091,29 @@ 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;
uint64_t totalCollateralsDUSD = 0;
uint64_t totalCollateralsDFI = 0;

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

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

if (static_cast<int>(height) < consensus.FortCanningHillHeight) {
if (totalCollaterals < collateralsLoans.val->totalCollaterals / 2)
if (static_cast<int>(height) < consensus.FortCanningHillHeight
&& totalCollateralsDUSD < collateralsLoans.val->totalCollaterals / 2){
dcorral marked this conversation as resolved.
Show resolved Hide resolved
return Res::Err("At least 50%% of the collateral must be in DFI");
} else {
if (hasDUSDLoans
&& arith_uint256(totalCollateralsDFI) * 100 < arith_uint256(collateralsLoans.val->totalLoans) * scheme->ratio / 2
&& static_cast<int>(height) >= consensus.FortCanningEpilogueHeight){
return Res::Err("At least 50%% of the minimum required collateral must be in DFI");
}
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");
Expand Down Expand Up @@ -3108,6 +3152,14 @@ 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 +3173,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 All @@ -3133,14 +3189,14 @@ class CCustomTxApplyVisitor : public CCustomTxVisitor
const auto totalInterest = TotalInterest(*rate, height);

if (totalInterest < 0) {
loanAmountChange = currentLoanAmount > std::abs(totalInterest) ?
loanAmountChange = currentLoanAmount > std::abs(totalInterest) ?
// Interest to decrease smaller than overall existing loan amount.
// So reduce interest from the borrowing principal. If this is negative,
// we'll reduce from principal.
tokenAmount + totalInterest :
// we'll reduce from principal.
tokenAmount + totalInterest :
// Interest to decrease is larger than old loan amount.
// We reduce from the borrowing principal. If this is negative,
// we'll reduce from principal.
// We reduce from the borrowing principal. If this is negative,
// we'll reduce from principal.
tokenAmount - currentLoanAmount;
resetInterestToHeight = true;
}
Expand Down Expand Up @@ -3201,10 +3257,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,17 +3269,28 @@ 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;
uint64_t totalCollateralsDUSD = 0;
uint64_t totalCollateralsDFI = 0;

for (auto& col : collateralsLoans.val->collaterals)
if (col.nTokenId == DCT_ID{0}
|| (tokenDUSD && col.nTokenId == tokenDUSD->first))
totalCollaterals += col.nValue;
for (auto& col : collateralsLoans.val->collaterals){
if (col.nTokenId == DCT_ID{0} ){
totalCollateralsDFI += col.nValue;
}
if(tokenDUSD && col.nTokenId == tokenDUSD->first){
totalCollateralsDUSD += 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.");
uint64_t totalCollaterals = totalCollateralsDUSD + totalCollateralsDFI;
if (static_cast<int>(height) < consensus.FortCanningHillHeight
&& totalCollateralsDUSD < collateralsLoans.val->totalCollaterals / 2){
dcorral marked this conversation as resolved.
Show resolved Hide resolved
return Res::Err("At least 50%% of the collateral must be in DFI when taking a loan.");
} else {
if (hasDUSDLoans
&& arith_uint256(totalCollateralsDFI) * 100 < arith_uint256(collateralsLoans.val->totalLoans) * scheme->ratio / 2
&& static_cast<int>(height) >= consensus.FortCanningEpilogueHeight){
return Res::Err("At least 50%% of the minimum required collateral must be in DFI");
}
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.");
Expand Down
Loading