From 61309ebc2307fa548269a838597e18f3667046ab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=9Fingen?= Date: Mon, 22 Mar 2021 19:16:23 +0100 Subject: [PATCH] contracts: migration simulation: Test migration simulation --- README.md | 6 +- .../TestContracts/TroveManagerNoBootstrap.sol | 10 + packages/contracts/contracts/TroveManager.sol | 2 +- packages/contracts/tests/helpers.py | 150 +++++++++++- packages/contracts/tests/migration_helpers.py | 229 ++++++++++++++++++ packages/contracts/tests/migration_test.py | 67 +++++ .../contracts/tests/simulation_helpers.py | 1 - packages/contracts/tests/simulation_test.py | 148 +---------- 8 files changed, 463 insertions(+), 150 deletions(-) create mode 100644 packages/contracts/contracts/TestContracts/TroveManagerNoBootstrap.sol create mode 100644 packages/contracts/tests/migration_helpers.py create mode 100644 packages/contracts/tests/migration_test.py diff --git a/README.md b/README.md index 0a12f5a7a..770bab0dd 100644 --- a/README.md +++ b/README.md @@ -618,7 +618,8 @@ brownie pm install OpenZeppelin/openzeppelin-contracts@3.3.0 Run, from `packages/contracts/`: ``` -brownie test -s +brownie test tests/simulation_test.py -s +brownie test tests/migration_test.py -s ``` ### OpenEthereum @@ -644,7 +645,8 @@ yarn start-dev-chain:openethereum Then, again from `packages/contracts/`, run it with: ``` -brownie test -s --network openethereum +brownie test tests/simulation_test.py -s --network openethereum +brownie test tests/migration_test.py -s --network openethereum ``` To stop the Openethereum node, you can do it with: diff --git a/packages/contracts/contracts/TestContracts/TroveManagerNoBootstrap.sol b/packages/contracts/contracts/TestContracts/TroveManagerNoBootstrap.sol new file mode 100644 index 000000000..0b6d0d00e --- /dev/null +++ b/packages/contracts/contracts/TestContracts/TroveManagerNoBootstrap.sol @@ -0,0 +1,10 @@ +// SPDX-License-Identifier: MIT + +pragma solidity 0.6.11; + +import "../TroveManager.sol"; + + +contract TroveManagerNoBootstrap is TroveManager { + function _requireAfterBootstrapPeriod() internal view override {} +} diff --git a/packages/contracts/contracts/TroveManager.sol b/packages/contracts/contracts/TroveManager.sol index 2a903f82d..5ffe6f4a4 100644 --- a/packages/contracts/contracts/TroveManager.sol +++ b/packages/contracts/contracts/TroveManager.sol @@ -1488,7 +1488,7 @@ contract TroveManager is LiquityBase, Ownable, CheckContract, ITroveManager { require(_getTCR(_price) >= MCR, "TroveManager: Cannot redeem when TCR < MCR"); } - function _requireAfterBootstrapPeriod() internal view { + function _requireAfterBootstrapPeriod() internal view virtual { uint systemDeploymentTime = lqtyToken.getDeploymentStartTime(); require(block.timestamp >= systemDeploymentTime.add(BOOTSTRAP_PERIOD), "TroveManager: Redemptions are not allowed during bootstrap phase"); } diff --git a/packages/contracts/tests/helpers.py b/packages/contracts/tests/helpers.py index 9e7a9087c..6f0dd6f80 100644 --- a/packages/contracts/tests/helpers.py +++ b/packages/contracts/tests/helpers.py @@ -1,13 +1,21 @@ -from brownie import Wei +import pytest + +from brownie import * +from accounts import * ZERO_ADDRESS = '0x' + '0'.zfill(40) MAX_BYTES_32 = '0x' + 'F' * 64 +MAX_FEE = Wei(1e18) + +class Contracts: pass def floatToWei(amount): return Wei(amount * 1e18) -def logGlobalState(contracts): +def logGlobalState(contracts, message=""): print('\n ---- Global state ----') + if message != "": + print(message) print('Num troves ', contracts.sortedTroves.getSize()) activePoolColl = contracts.activePool.getETH() activePoolDebt = contracts.activePool.getLUSDDebt() @@ -32,3 +40,141 @@ def logGlobalState(contracts): #print('Last trove ', last_trove) print('Last trove’s ICR', last_ICR.to("ether")) print(' ----------------------\n') + +def setAddresses(contracts): + contracts.sortedTroves.setParams( + MAX_BYTES_32, + contracts.troveManager.address, + contracts.borrowerOperations.address, + { 'from': accounts[0] } + ) + + contracts.troveManager.setAddresses( + contracts.borrowerOperations.address, + contracts.activePool.address, + contracts.defaultPool.address, + contracts.stabilityPool.address, + contracts.gasPool.address, + contracts.collSurplusPool.address, + contracts.priceFeedTestnet.address, + contracts.lusdToken.address, + contracts.sortedTroves.address, + contracts.lqtyToken.address, + contracts.lqtyStaking.address, + { 'from': accounts[0] } + ) + + contracts.borrowerOperations.setAddresses( + contracts.troveManager.address, + contracts.activePool.address, + contracts.defaultPool.address, + contracts.stabilityPool.address, + contracts.gasPool.address, + contracts.collSurplusPool.address, + contracts.priceFeedTestnet.address, + contracts.sortedTroves.address, + contracts.lusdToken.address, + contracts.lqtyStaking.address, + { 'from': accounts[0] } + ) + + contracts.stabilityPool.setAddresses( + contracts.borrowerOperations.address, + contracts.troveManager.address, + contracts.activePool.address, + contracts.lusdToken.address, + contracts.sortedTroves.address, + contracts.priceFeedTestnet.address, + contracts.communityIssuance.address, + { 'from': accounts[0] } + ) + + contracts.activePool.setAddresses( + contracts.borrowerOperations.address, + contracts.troveManager.address, + contracts.stabilityPool.address, + contracts.defaultPool.address, + { 'from': accounts[0] } + ) + + contracts.defaultPool.setAddresses( + contracts.troveManager.address, + contracts.activePool.address, + { 'from': accounts[0] } + ) + + contracts.collSurplusPool.setAddresses( + contracts.borrowerOperations.address, + contracts.troveManager.address, + contracts.activePool.address, + { 'from': accounts[0] } + ) + + contracts.hintHelpers.setAddresses( + contracts.sortedTroves.address, + contracts.troveManager.address, + { 'from': accounts[0] } + ) + + # LQTY + contracts.lqtyStaking.setAddresses( + contracts.lqtyToken.address, + contracts.lusdToken.address, + contracts.troveManager.address, + contracts.borrowerOperations.address, + contracts.activePool.address, + { 'from': accounts[0] } + ) + + contracts.communityIssuance.setAddresses( + contracts.lqtyToken.address, + contracts.stabilityPool.address, + { 'from': accounts[0] } + ) + +def deploy_contracts(): + contracts = Contracts() + + contracts.priceFeedTestnet = PriceFeedTestnet.deploy({ 'from': accounts[0] }) + contracts.sortedTroves = SortedTroves.deploy({ 'from': accounts[0] }) + #contracts.troveManager = TroveManager.deploy({ 'from': accounts[0] }) + contracts.troveManager = TroveManagerNoBootstrap.deploy({ 'from': accounts[0] }) + contracts.activePool = ActivePool.deploy({ 'from': accounts[0] }) + contracts.stabilityPool = StabilityPool.deploy({ 'from': accounts[0] }) + contracts.gasPool = GasPool.deploy({ 'from': accounts[0] }) + contracts.defaultPool = DefaultPool.deploy({ 'from': accounts[0] }) + contracts.collSurplusPool = CollSurplusPool.deploy({ 'from': accounts[0] }) + contracts.borrowerOperations = BorrowerOperations.deploy({ 'from': accounts[0] }) + contracts.hintHelpers = HintHelpers.deploy({ 'from': accounts[0] }) + contracts.lusdToken = LUSDToken.deploy( + contracts.troveManager.address, + contracts.stabilityPool.address, + contracts.borrowerOperations.address, + { 'from': accounts[0] } + ) + # LQTY + contracts.lqtyStaking = LQTYStaking.deploy({ 'from': accounts[0] }) + contracts.communityIssuance = CommunityIssuance.deploy({ 'from': accounts[0] }) + contracts.lockupContractFactory = LockupContractFactory.deploy({ 'from': accounts[0] }) + contracts.lqtyToken = LQTYToken.deploy( + contracts.communityIssuance.address, + contracts.lqtyStaking.address, + contracts.lockupContractFactory.address, + accounts[1], # bountyAddress + accounts[1], # lpRewardsAddress + { 'from': accounts[0] } + ) + + setAddresses(contracts) + + return contracts + +@pytest.fixture +@pytest.mark.require_network("openethereum") +def add_accounts(scope="module"): + import_accounts(accounts) + """ + if network.show_active() != 'development': + print("Importing accounts...") + import_accounts(accounts) + """ diff --git a/packages/contracts/tests/migration_helpers.py b/packages/contracts/tests/migration_helpers.py new file mode 100644 index 000000000..2bf07fb60 --- /dev/null +++ b/packages/contracts/tests/migration_helpers.py @@ -0,0 +1,229 @@ +from brownie import Wei + +import random + +from helpers import * + +ETHER_PRICE = Wei(1000 * 1e18) +LUSD_GAS_COMPENSATION = Wei(50 * 1e18) + +NONE = 0 +CLOSED = 1 +REDEEMED = 2 +ALREADY_CLOSED = 3 +CLOSE_FAILED = -1 +OPEN_FAILED = -2 + +# Subtracts the borrowing fee +def get_lusd_amount_from_net_debt(contracts, net_debt): + borrowing_rate = contracts.troveManager.getBorrowingRateWithDecay() + return Wei(net_debt * Wei(1e18) / (Wei(1e18) + borrowing_rate)) + +# Subtracts the gas reserve and the borrowing fee +def get_lusd_amount_from_total_debt(contracts, total_debt): + net_debt = total_debt - LUSD_GAS_COMPENSATION + return get_lusd_amount_from_net_debt(contracts, net_debt) + +def flesh_out_system(accounts, contracts): + LUSD_GAS_COMPENSATION = contracts.troveManager.LUSD_GAS_COMPENSATION() + + MIN_NET_DEBT = contracts.troveManager.MIN_NET_DEBT() + MIN_LUSD_AMOUNT = get_lusd_amount_from_net_debt(contracts, MIN_NET_DEBT) + Wei(1e18) + + # Account 0 will always be the last one, as one has to remain in the system + collateral = Wei(MIN_NET_DEBT * 6 * 1e18 / ETHER_PRICE) # ICR: ~600% (missing gas reserve) + contracts.borrowerOperations.openTrove(MAX_FEE, MIN_LUSD_AMOUNT, ZERO_ADDRESS, ZERO_ADDRESS, + { 'from': accounts[0], 'value': collateral }) + + # send 1 lqty token to account 1 (deployer cannot stake during 1st year), + #contracts.lqtyToken.transfer(accounts[1], 1, { 'from': accounts[0] }) + # account 1 stakes to earn borrowing fees + contracts.lqtyStaking.stake(1, { 'from': accounts[1] }) + + # open trove in ICR descending order + ICR = 500 + for i in range(1, 1000): + lusd_amount = MIN_LUSD_AMOUNT + floatToWei(1000000 * random.random()) # lusd ranging from min to 1M + borrowing_fee = contracts.troveManager.getBorrowingFeeWithDecay(lusd_amount) + if ICR < 120: + ICR = ICR - 0.01 + else: + ICR = ICR - 0.76 * random.random() # last trove ICR should be at ~ 500 - 999*0.76*0.5 = 120.38 + coll = Wei((lusd_amount + borrowing_fee + LUSD_GAS_COMPENSATION) * floatToWei(ICR / 100) / ETHER_PRICE) + try: + contracts.borrowerOperations.openTrove(MAX_FEE, lusd_amount, accounts[i-1], ZERO_ADDRESS, + { 'from': accounts[i], 'value': coll }) + except: + print("\n Opening trove failed! \n") + print(f"Borrower Operations: {contracts.borrowerOperations.address}") + print(f"i: {i}") + print(f"account: {accounts[i]}") + print(f"ICR: {ICR}") + print(f"coll: {coll}") + print(f"debt: {lusd_amount}") + exit(1) + + # claim LUSD gain from LQTY Staking + contracts.lqtyStaking.unstake(0, { 'from': accounts[1] }) + +def get_lusd_to_repay(accounts, contracts, account, debt): + if account == accounts[1]: + return + lusd_balance = contracts.lusdToken.balanceOf(account) + pending = Wei(0) + + if debt > lusd_balance: + pending = debt - lusd_balance + sender_balance = contracts.lusdToken.balanceOf(accounts[1]) + if sender_balance < pending: + print(f"\n ***Error: not enough LUSD to repay! {debt / 1e18} LUSD for {account}, pending {pending / 1e18}, sender balance {sender_balance / 1e18}") + return + + contracts.lusdToken.transfer(account, pending, { 'from': accounts[1] }) + + return lusd_balance + pending + +def migrate_trove(accounts, contracts1, contracts2, i, upper_hint=None, lower_hint=None): + result = NONE + # [debt, coll] = contracts1.troveManager.getEntireDebtAndColl(accounts[i]) + trove = contracts1.troveManager.getEntireDebtAndColl(accounts[i]) + debt = trove[0] + coll = trove[1] + get_lusd_to_repay(accounts, contracts1, accounts[i], debt - LUSD_GAS_COMPENSATION) + + total_coll = contracts1.troveManager.getEntireSystemColl() - coll + total_debt = contracts1.troveManager.getEntireSystemDebt() - debt + # Trove may have been closed by a redemption + trove_status = contracts1.troveManager.getTroveStatus(accounts[i]) + if trove_status != Wei(1): + # TODO: claim remaining collateral and then open + return ALREADY_CLOSED + TCR = contracts1.hintHelpers.computeCR(total_coll, total_debt, ETHER_PRICE) + if TCR >= Wei(150 * 1e16): + # close trove in old system + try: + contracts1.borrowerOperations.closeTrove({ 'from': accounts[i] }) + result = CLOSED + except: + print("\n Closing trove failed! \n") + print(f"Borrower Operations: {contracts1.borrowerOperations.address}") + print(f"i: {i}") + print(f"account: {accounts[i]}") + print(f"coll: {coll}") + print(f"debt: {debt}") + return CLOSE_FAILED + else: + print(f"After account {i}, resulting TCR: {TCR / 1e18}, redeeming") + if redeem_trove(accounts, contracts1, i): + # TODO: try to claim remaining collateral (if any) and then open + return REDEEMED + + # open trove in new system + try: + if not upper_hint or not lower_hint: + NICR = contracts2.hintHelpers.computeNominalCR(coll, debt) + [upper_hint, lower_hint] = contracts2.sortedTroves.findInsertPosition(NICR, ZERO_ADDRESS, ZERO_ADDRESS) + + lusd_amount = get_lusd_amount_from_total_debt(contracts2, debt) + + #coll = Wei((lusd_amount + borrowing_fee + LUSD_GAS_COMPENSATION) * floatToWei(ICR / 100) / ETHER_PRICE) + contracts2.borrowerOperations.openTrove(MAX_FEE, lusd_amount, upper_hint, lower_hint, + { 'from': accounts[i], 'value': coll }) + except: + print("\n Opening trove in the new system failed! \n") + print(f"Borrower Operations: {contracts2.borrowerOperations.address}") + print(f"i: {i}") + print(f"account: {accounts[i]}") + print(f"coll: {coll}") + print(f"lusd: {lusd_amount}") + print(f"ICR: {coll * ETHER_PRICE / debt / 1e18}") + print(f"ETH bal : {accounts[i].balance()}") + print(f"LUSD bal: {contracts2.lusdToken.balanceOf(accounts[i])}") + print(f"upper hint: {upper_hint}") + print(f"NICR: {contracts2.troveManager.getNominalICR(upper_hint)}") + print(f"lower hint: {lower_hint}") + print(f"NICR: {contracts2.troveManager.getNominalICR(lower_hint)}") + last = contracts2.sortedTroves.getLast() + print(f"last trove: {last}") + print(f"NICR: {contracts2.troveManager.getNominalICR(last)}") + return OPEN_FAILED + + return result + +def redeem_trove(accounts, contracts, i): + lusd_balance = contracts.lusdToken.balanceOf(accounts[i]) + [firstRedemptionHint, partialRedemptionHintNICR, truncatedLUSDamount] = contracts.hintHelpers.getRedemptionHints(lusd_balance, ETHER_PRICE, 70) + if truncatedLUSDamount == Wei(0): + return False + approxHint = contracts.hintHelpers.getApproxHint(partialRedemptionHintNICR, 2000, 0) + hints = contracts.sortedTroves.findInsertPosition(partialRedemptionHintNICR, approxHint[0], approxHint[0]) + try: + contracts.troveManager.redeemCollateral( + truncatedLUSDamount, + firstRedemptionHint, + hints[0], + hints[1], + partialRedemptionHintNICR, + 70, + MAX_FEE, + { 'from': accounts[i], 'gas_limit': 8000000, 'allow_revert': True } + ) + except: + print(f"\n Redemption failed! ") + print(f"Trove Manager: {contracts.troveManager.address}") + print(f"LUSD Token: {contracts.lusdToken.address}") + print(f"i: {i}") + print(f"account: {accounts[i]}") + print(f"LUSD bal: {lusd_balance / 1e18}") + print(f"truncated: {truncatedLUSDamount / 1e18}") + print(f"Redemption rate: {contracts.troveManager.getRedemptionRateWithDecay() * 100 / 1e18} %") + print(f"approx: {approxHint[0]}") + print(f"diff: {approxHint[1]}") + print(f"diff: {approxHint[1] / 1e18}") + print(f"seed: {approxHint[2]}") + print(f"amount: {truncatedLUSDamount}") + print(f"first: {firstRedemptionHint}") + print(f"hint: {hints[0]}") + print(f"hint: {hints[1]}") + print(f"nicr: {partialRedemptionHintNICR}") + print(f"nicr: {partialRedemptionHintNICR / 1e18}") + print(f"70") + print(f"{MAX_FEE}") + exit(1) + + return True + +def run_migration_desc(accounts, contracts1, contracts2): + # redemption break the previous order + redemption_happened = False + for i in range(1, 1000): + if redemption_happened: + upper_hint = None + lower_hint = None + else: + upper_hint = contracts2.sortedTroves.getLast() + lower_hint = ZERO_ADDRESS + + result = migrate_trove(accounts, contracts1, contracts2, i, upper_hint, lower_hint) + if result == REDEEMED: + redemption_happened = True + if result < 0: + break + if redemption_happened: + # TODO: make another pass to claim remaining collateral, close troves, and re-open + pass + +def run_migration_asc(accounts, contracts1, contracts2): + for i in range(999, 0, -1): + migrate_trove(accounts, contracts1, contracts2, i, ZERO_ADDRESS, contracts2.sortedTroves.getFirst()) + +def run_migration_rand(accounts, contracts1, contracts2): + remaining = list(range(1, 1000)) + while(len(remaining) > 0): + i = random.randrange(0, len(remaining)) + migrate_trove(accounts, contracts1, contracts2, remaining[i]) + remaining.pop(i) + +def run_migration_redeem(accounts, contracts1, contracts2): + for i in range(1, 1000): + redeem_trove(accounts, contracts1, i) diff --git a/packages/contracts/tests/migration_test.py b/packages/contracts/tests/migration_test.py new file mode 100644 index 000000000..438db3d35 --- /dev/null +++ b/packages/contracts/tests/migration_test.py @@ -0,0 +1,67 @@ +import pytest + +from helpers import * +from migration_helpers import * + +def _setup(): + contracts1 = deploy_contracts() + contracts1.priceFeedTestnet.setPrice(ETHER_PRICE, { 'from': accounts[0] }) + + flesh_out_system(accounts, contracts1) + + logGlobalState(contracts1, message="contracts1 initial") + + contracts2 = deploy_contracts() + contracts2.priceFeedTestnet.setPrice(ETHER_PRICE, { 'from': accounts[0] }) + + logGlobalState(contracts2, message="contracts2 initial") + + # fast forward the bootstrap phase to allow redemptions + # doesn’t work with OpenEthereum + # chain.sleep(14 * 24 * 60 * 60) + # chain.mine() + + return [contracts1, contracts2] + +def test_run_migration_desc(add_accounts): + [contracts1, contracts2] = _setup() + + # migrate troves in ICR descending order + run_migration_desc(accounts, contracts1, contracts2) + + logGlobalState(contracts1, message="contracts1 final") + logGlobalState(contracts2, message="contracts2 final") + +""" +# It fails at the first attempt, because first trove in the new system is < CCR +def test_run_migration_asc(add_accounts): + [contracts1, contracts2] = _setup() + + # migrate troves in ICR ascending order + run_migration_asc(accounts, contracts1, contracts2) + + logGlobalState(contracts1) + logGlobalState(contracts2) +""" + +def test_run_migration_rand(add_accounts): + [contracts1, contracts2] = _setup() + + # migrate troves in ICR random order + run_migration_rand(accounts, contracts1, contracts2) + + logGlobalState(contracts1) + logGlobalState(contracts2) + +""" +# It doesn’t make sense because redemption rate ends up growing too much. +def test_run_migration_redeem(add_accounts): + [contracts1, contracts2] = _setup() + + # migrate troves in ICR random order + run_migration_redeem(accounts, contracts1, contracts2) + + logGlobalState(contracts1) + logGlobalState(contracts2) +""" + diff --git a/packages/contracts/tests/simulation_helpers.py b/packages/contracts/tests/simulation_helpers.py index abdc6375b..ac08b5bc1 100644 --- a/packages/contracts/tests/simulation_helpers.py +++ b/packages/contracts/tests/simulation_helpers.py @@ -19,7 +19,6 @@ NUM_LIQUIDATIONS = 10 MIN_NET_DEBT = 1950.0 -MAX_FEE = Wei(1e18) """# Ether price (exogenous) diff --git a/packages/contracts/tests/simulation_test.py b/packages/contracts/tests/simulation_test.py index 3146eea9b..795f691ed 100644 --- a/packages/contracts/tests/simulation_test.py +++ b/packages/contracts/tests/simulation_test.py @@ -1,147 +1,10 @@ import pytest from brownie import * -from accounts import * + from helpers import * from simulation_helpers import * -class Contracts: pass - - -def setAddresses(contracts): - contracts.sortedTroves.setParams( - MAX_BYTES_32, - contracts.troveManager.address, - contracts.borrowerOperations.address, - { 'from': accounts[0] } - ) - - contracts.troveManager.setAddresses( - contracts.borrowerOperations.address, - contracts.activePool.address, - contracts.defaultPool.address, - contracts.stabilityPool.address, - contracts.gasPool.address, - contracts.collSurplusPool.address, - contracts.priceFeedTestnet.address, - contracts.lusdToken.address, - contracts.sortedTroves.address, - contracts.lqtyToken.address, - contracts.lqtyStaking.address, - { 'from': accounts[0] } - ) - - contracts.borrowerOperations.setAddresses( - contracts.troveManager.address, - contracts.activePool.address, - contracts.defaultPool.address, - contracts.stabilityPool.address, - contracts.gasPool.address, - contracts.collSurplusPool.address, - contracts.priceFeedTestnet.address, - contracts.sortedTroves.address, - contracts.lusdToken.address, - contracts.lqtyStaking.address, - { 'from': accounts[0] } - ) - - contracts.stabilityPool.setAddresses( - contracts.borrowerOperations.address, - contracts.troveManager.address, - contracts.activePool.address, - contracts.lusdToken.address, - contracts.sortedTroves.address, - contracts.priceFeedTestnet.address, - contracts.communityIssuance.address, - { 'from': accounts[0] } - ) - - contracts.activePool.setAddresses( - contracts.borrowerOperations.address, - contracts.troveManager.address, - contracts.stabilityPool.address, - contracts.defaultPool.address, - { 'from': accounts[0] } - ) - - contracts.defaultPool.setAddresses( - contracts.troveManager.address, - contracts.activePool.address, - { 'from': accounts[0] } - ) - - contracts.collSurplusPool.setAddresses( - contracts.borrowerOperations.address, - contracts.troveManager.address, - contracts.activePool.address, - { 'from': accounts[0] } - ) - - contracts.hintHelpers.setAddresses( - contracts.sortedTroves.address, - contracts.troveManager.address, - { 'from': accounts[0] } - ) - - # LQTY - contracts.lqtyStaking.setAddresses( - contracts.lqtyToken.address, - contracts.lusdToken.address, - contracts.troveManager.address, - contracts.borrowerOperations.address, - contracts.activePool.address, - { 'from': accounts[0] } - ) - - contracts.communityIssuance.setAddresses( - contracts.lqtyToken.address, - contracts.stabilityPool.address, - { 'from': accounts[0] } - ) - -@pytest.fixture -def add_accounts(): - if network.show_active() != 'development': - print("Importing accounts...") - import_accounts(accounts) - -@pytest.fixture -def contracts(): - contracts = Contracts() - - contracts.priceFeedTestnet = PriceFeedTestnet.deploy({ 'from': accounts[0] }) - contracts.sortedTroves = SortedTroves.deploy({ 'from': accounts[0] }) - contracts.troveManager = TroveManager.deploy({ 'from': accounts[0] }) - contracts.activePool = ActivePool.deploy({ 'from': accounts[0] }) - contracts.stabilityPool = StabilityPool.deploy({ 'from': accounts[0] }) - contracts.gasPool = GasPool.deploy({ 'from': accounts[0] }) - contracts.defaultPool = DefaultPool.deploy({ 'from': accounts[0] }) - contracts.collSurplusPool = CollSurplusPool.deploy({ 'from': accounts[0] }) - contracts.borrowerOperations = BorrowerOperations.deploy({ 'from': accounts[0] }) - contracts.hintHelpers = HintHelpers.deploy({ 'from': accounts[0] }) - contracts.lusdToken = LUSDToken.deploy( - contracts.troveManager.address, - contracts.stabilityPool.address, - contracts.borrowerOperations.address, - { 'from': accounts[0] } - ) - # LQTY - contracts.lqtyStaking = LQTYStaking.deploy({ 'from': accounts[0] }) - contracts.communityIssuance = CommunityIssuance.deploy({ 'from': accounts[0] }) - contracts.lockupContractFactory = LockupContractFactory.deploy({ 'from': accounts[0] }) - contracts.lqtyToken = LQTYToken.deploy( - contracts.communityIssuance.address, - contracts.lqtyStaking.address, - contracts.lockupContractFactory.address, - accounts[0], # bountyAddress - accounts[0], # lpRewardsAddress - { 'from': accounts[0] } - ) - - setAddresses(contracts) - - return contracts - @pytest.fixture def print_expectations(): ether_price_one_year = price_ether_initial * (1 + drift_ether)**8760 @@ -156,12 +19,9 @@ def print_expectations(): print("SD(tau) = ", rational_inattention_gamma_k**(0.5) * rational_inattention_gamma_theta * 100, "%") print("\n") -def _test_test(contracts): - print(len(accounts)) - contracts.borrowerOperations.openTrove(Wei(1e18), Wei(2000e18), ZERO_ADDRESS, ZERO_ADDRESS, - { 'from': accounts[1], 'value': Wei("100 ether") }) - - #assert False +@pytest.fixture +def contracts(): + return deploy_contracts() """# Simulation Program **Sequence of events**