Skip to content

Commit

Permalink
DVM: Enable DUSD loops in vaults (#1971)
Browse files Browse the repository at this point in the history
* allow DUSD Loops with 100% DUSD coll

* added tests

* fix lint errors

* fix tests

* added gc height to test

* added testcases

* lint

* fix test

* test: fix oracle

* tests: fix oracle update in tests.

---------

Co-authored-by: Peter John Bushnell <[email protected]>
  • Loading branch information
kuegi and Bushstar committed Jun 21, 2023
1 parent 3d51c31 commit 6d30278
Show file tree
Hide file tree
Showing 4 changed files with 114 additions and 1 deletion.
6 changes: 5 additions & 1 deletion src/masternodes/govvariables/attributes.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,7 @@ const std::map<uint8_t, std::map<std::string, uint8_t>> &ATTRIBUTES::allowedKeys
{"gov-payout", DFIPKeys::CFPPayout},
{"emission-unused-fund", DFIPKeys::EmissionUnusedFund},
{"mint-tokens-to-address", DFIPKeys::MintTokens},
{"allow-dusd-loops", DFIPKeys::AllowDUSDLoops},
}},
{AttributeTypes::Governance,
{
Expand Down Expand Up @@ -273,6 +274,7 @@ const std::map<uint8_t, std::map<uint8_t, std::string>> &ATTRIBUTES::displayKeys
{DFIPKeys::CFPPayout, "gov-payout"},
{DFIPKeys::EmissionUnusedFund, "emission-unused-fund"},
{DFIPKeys::MintTokens, "mint-tokens-to-address"},
{DFIPKeys::AllowDUSDLoops, "allow-dusd-loops"},
}},
{AttributeTypes::Live,
{
Expand Down Expand Up @@ -601,6 +603,7 @@ const std::map<uint8_t, std::map<uint8_t, std::function<ResVal<CAttributeValue>(
{DFIPKeys::CFPPayout, VerifyBool},
{DFIPKeys::EmissionUnusedFund, VerifyBool},
{DFIPKeys::MintTokens, VerifyBool},
{DFIPKeys::AllowDUSDLoops, VerifyBool},
}},
{AttributeTypes::Locks,
{
Expand Down Expand Up @@ -811,7 +814,8 @@ Res ATTRIBUTES::ProcessVariable(const std::string &key,
typeKey != DFIPKeys::MNSetOwnerAddress && typeKey != DFIPKeys::GovernanceEnabled &&
typeKey != DFIPKeys::ConsortiumEnabled && typeKey != DFIPKeys::CFPPayout &&
typeKey != DFIPKeys::EmissionUnusedFund && typeKey != DFIPKeys::MintTokens &&
typeKey != DFIPKeys::EVMEnabled && typeKey != DFIPKeys::ICXEnabled) {
typeKey != DFIPKeys::EVMEnabled && typeKey != DFIPKeys::ICXEnabled &&
typeKey != DFIPKeys::AllowDUSDLoops) {
return DeFiErrors::GovVarVariableUnsupportedFeatureType(typeKey);
}
} else if (typeId == ParamIDs::Foundation) {
Expand Down
1 change: 1 addition & 0 deletions src/masternodes/govvariables/attributes.h
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ enum DFIPKeys : uint8_t {
MintTokens = 't',
EVMEnabled = 'u',
ICXEnabled = 'v',
AllowDUSDLoops = 'w',
};

enum GovernanceKeys : uint8_t {
Expand Down
19 changes: 19 additions & 0 deletions src/masternodes/mn_checks.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3009,6 +3009,10 @@ class CCustomTxApplyVisitor : public CCustomTxVisitor {
CAmount factorDUSD = 0;
CAmount factorDFI = 0;


auto hasDUSDColl = false;
auto hasOtherColl = false;

for (auto &col : vaultAssets.collaterals) {
auto token = mnview.GetCollateralTokenFromAttributes(col.nTokenId);

Expand All @@ -3020,6 +3024,9 @@ class CCustomTxApplyVisitor : public CCustomTxVisitor {
if (tokenDUSD && col.nTokenId == tokenDUSD->first) {
totalCollateralsDUSD += col.nValue;
factorDUSD = token->factor;
hasDUSDColl= true;
} else {
hasOtherColl = true;
}
}

Expand All @@ -3029,6 +3036,18 @@ class CCustomTxApplyVisitor : public CCustomTxVisitor {
auto isPostFCE = static_cast<int>(height) >= consensus.FortCanningEpilogueHeight;
auto isPostFCR = static_cast<int>(height) >= consensus.FortCanningRoadHeight;
auto isPostGC = static_cast<int>(height) >= consensus.GrandCentralHeight;
auto isPostNext = static_cast<int>(height) >= consensus.NextNetworkUpgradeHeight;

if(isPostNext) {
const CDataStructureV0 enabledKey{AttributeTypes::Param, ParamIDs::Feature, DFIPKeys::AllowDUSDLoops};
auto attributes = mnview.GetAttributes();
assert(attributes);
auto DUSDLoopsAllowed= attributes->GetValue(enabledKey, false);
if(DUSDLoopsAllowed && hasDUSDColl && !hasOtherColl) {
return Res::Ok(); //every loan ok when DUSD loops allowed and 100% DUSD collateral
}
}


if (isPostGC) {
totalCollateralsDUSD = MultiplyAmounts(totalCollateralsDUSD, factorDUSD);
Expand Down
89 changes: 89 additions & 0 deletions test/functional/feature_dusd_loans.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,10 @@ def set_test_params(self):
self.fortcanningroadheight = 2000
self.fortcanninggreatworldheight = 3000
self.fortcanningepilogueheight = 4000
self.grandcentralheight = 4500
self.grandcentralepilogueheight = 5000
self.nextnetworkupgradeheight = 6000

self.extra_args = [
['-txnotokens=0',
'-amkheight=1',
Expand All @@ -43,6 +47,10 @@ def set_test_params(self):
f'-fortcanningroadheight={self.fortcanningroadheight}',
f'-fortcanninggreatworldheight={self.fortcanninggreatworldheight}',
f'-fortcanningepilogueheight={self.fortcanningepilogueheight}',
f'-grandcentralheight={self.grandcentralheight}',
f'-grandcentralepilogueheight={self.grandcentralepilogueheight}',
f'-nextnetworkupgradeheight={self.nextnetworkupgradeheight}',

'-jellyfish_regtest=1', '-txindex=1', '-simulatemainnet=1']
]

Expand Down Expand Up @@ -110,6 +118,20 @@ def goto_fce_height(self):
blockchainInfo = self.nodes[0].getblockchaininfo()
assert_equal(blockchainInfo["softforks"]["fortcanningepilogue"]["active"], True)

def goto_gce_height(self):
blockHeight = self.nodes[0].getblockcount()
if self.grandcentralepilogueheight > blockHeight:
self.nodes[0].generate((self.grandcentralepilogueheight - blockHeight) + 2)
blockchainInfo = self.nodes[0].getblockchaininfo()
assert_equal(blockchainInfo["softforks"]["grandcentralepilogue"]["active"], True)

def goto_next_height(self):
blockHeight = self.nodes[0].getblockcount()
if self.nextnetworkupgradeheight > blockHeight:
self.nodes[0].generate((self.nextnetworkupgradeheight - blockHeight) + 2)
blockchainInfo = self.nodes[0].getblockchaininfo()
assert_equal(blockchainInfo["softforks"]["nextnetworkupgrade"]["active"], True)

def create_tokens(self):
self.symbolDFI = "DFI"
self.symboldUSD = "DUSD"
Expand Down Expand Up @@ -504,6 +526,70 @@ def post_FCE_DFI_minimum_check_takeloan(self):
self.rollback_to(block_height)
self.rollback_checks([vault_id, vault_id_1])

def check_looped_dusd(self):
block_height = self.nodes[0].getblockcount()

vault_id = self.new_vault('LOAN1', ["100.00000000@DUSD"])

self.goto_gce_height()
assert_raises_rpc_error(-32600,
ERR_STRING_MIN_COLLATERAL_DFI_PCT,
self.takeloan_withdraw, vault_id, "1.00000000@DUSD", 'takeloan')

self.nodes[0].setgov({"ATTRIBUTES": {'v0/params/feature/allow-dusd-loops': 'true'}})
self.nodes[0].generate(1)

#still not allowed before hardfork
assert_raises_rpc_error(-32600,
ERR_STRING_MIN_COLLATERAL_DFI_PCT,
self.takeloan_withdraw, vault_id, "1.00000000@DUSD", 'takeloan')
self.goto_next_height()

# min coll ratio still applies
assert_raises_rpc_error(-32600,
"Vault does not have enough collateralization ratio defined by loan scheme - 148 < 150",
self.takeloan_withdraw, vault_id, "67.00000000@DUSD", 'takeloan')


self.nodes[0].generate(1)
self.takeloan_withdraw(vault_id, "1.00000000@DUSD", 'takeloan')
self.nodes[0].generate(1)
self.takeloan_withdraw(vault_id, "1.00000000@DUSD", 'withdraw')
self.nodes[0].generate(1)

# not sure why this is needed like this. but it works
self.update_oracle_price(13000)
#also fails with other crypto in
self.nodes[0].deposittovault(vault_id, self.account0, "100.00000000@BTC")
self.nodes[0].generate(1)
assert_raises_rpc_error(-32600,
ERR_STRING_MIN_COLLATERAL_DFI_PCT,
self.takeloan_withdraw, vault_id, "1.00000000@DUSD", 'takeloan')

assert_raises_rpc_error(-32600,
ERR_STRING_MIN_COLLATERAL_DFI_PCT,
self.takeloan_withdraw, vault_id, "5.00000000@BTC", 'withdraw')

# full withdrawal (go to 100% DUSD) should work
self.takeloan_withdraw(vault_id, "100.00000000@BTC", 'withdraw')
self.nodes[0].generate(1)


self.nodes[0].setgov({"ATTRIBUTES": {'v0/params/feature/allow-dusd-loops': 'false'}})
self.nodes[0].generate(1)

#not allowed if attribute false

assert_raises_rpc_error(-32600,
ERR_STRING_MIN_COLLATERAL_DFI_PCT,
self.takeloan_withdraw, vault_id, "1.00000000@DUSD", 'takeloan')
assert_raises_rpc_error(-32600,
ERR_STRING_MIN_COLLATERAL_DFI_PCT,
self.takeloan_withdraw, vault_id, "1.00000000@DUSD", 'withdraw')

self.rollback_to(block_height)
self.rollback_checks([vault_id])

def run_test(self):
# Initial set up
self.setup()
Expand All @@ -520,6 +606,9 @@ def run_test(self):
self.update_oracle_price()
self.post_FCE_DFI_minimum_check_takeloan()

self.update_oracle_price()
self.check_looped_dusd()

# self.post_FCE_DFI_minimum_check_withdraw()

# TODO
Expand Down

0 comments on commit 6d30278

Please sign in to comment.