diff --git a/brownie-config.yaml b/brownie-config.yaml index a473488..fcdbe59 100644 --- a/brownie-config.yaml +++ b/brownie-config.yaml @@ -12,8 +12,7 @@ compiler: # https://eth-brownie.readthedocs.io/en/stable/compile.html#compiler-settings remappings: - "@openzeppelin=OpenZeppelin/openzeppelin-contracts@4.7.0" - - "@gif-interface=etherisc/gif-interface@1.7.0-staging-k" - - "@etherisc/gif-interface=etherisc/gif-interface@1.7.0-staging-k" + - "@etherisc/gif-interface=etherisc/gif-interface@1.8.0-staging-f" vyper: version: null @@ -23,7 +22,7 @@ compiler: dependencies: # github dependency format: /@ - OpenZeppelin/openzeppelin-contracts@4.7.0 - - etherisc/gif-interface@1.7.0-staging-k + - etherisc/gif-interface@1.8.0-staging-f # exclude Ownable when calculating test coverage # https://eth-brownie.readthedocs.io/en/v1.10.3/config.html#exclude_paths diff --git a/contracts/modules/BundleController.sol b/contracts/modules/BundleController.sol index 9eaa5d2..f018fad 100644 --- a/contracts/modules/BundleController.sol +++ b/contracts/modules/BundleController.sol @@ -69,8 +69,7 @@ contract BundleController is emit LogBundleCreated(bundle.id, riskpoolId_, owner_, bundle.state, bundle.capital); } - // TODO decide + implement authz for risk bundle creation - // funding can come from nft owner or various 2nd level risk pool owners + function fund(uint256 bundleId, uint256 amount) external override onlyRiskpoolService @@ -87,6 +86,7 @@ contract BundleController is emit LogBundleCapitalProvided(bundleId, _msgSender(), amount, capacityAmount); } + function defund(uint256 bundleId, uint256 amount) external override onlyRiskpoolService @@ -94,11 +94,14 @@ contract BundleController is Bundle storage bundle = _bundles[bundleId]; require(bundle.createdAt > 0, "ERROR:BUC-013:BUNDLE_DOES_NOT_EXIST"); require( - bundle.capital >= bundle.lockedCapital + amount, - "ERROR:BUC-014:CAPACITY_TOO_LOW" + bundle.capital >= bundle.lockedCapital + amount + || (bundle.lockedCapital == 0 && bundle.balance >= amount), + "ERROR:BUC-014:CAPACITY_OR_BALANCE_TOO_LOW" ); - bundle.capital -= amount; + if (bundle.capital >= amount) { bundle.capital -= amount; } + else { bundle.capital = 0; } + bundle.balance -= amount; bundle.updatedAt = block.timestamp; @@ -128,14 +131,28 @@ contract BundleController is _changeState(bundleId, BundleState.Closed); } + function burn(uint256 bundleId) + external override + onlyRiskpoolService + { + Bundle storage bundle = _bundles[bundleId]; + require(bundle.state == BundleState.Closed, "ERROR:BUC-016:BUNDLE_NOT_CLOSED"); + require(bundle.balance == 0, "ERROR:BUC-016:BUNDLE_HAS_BALANCE"); + + // burn corresponding nft -> as a result bundle looses its owner + _token.burn(bundleId); + + _changeState(bundleId, BundleState.Burned); + } + function collateralizePolicy(uint256 bundleId, bytes32 processId, uint256 amount) external override onlyRiskpoolService { Bundle storage bundle = _bundles[bundleId]; - require(bundle.createdAt > 0, "ERROR:BUC-001:BUNDLE_DOES_NOT_EXIST"); - require(bundle.state == IBundle.BundleState.Active, "ERROR:BUC-005:BUNDLE_NOT_ACTIVE"); - require(bundle.capital >= bundle.lockedCapital + amount, "ERROR:BUC-006:CAPACITY_TOO_LOW"); + require(bundle.createdAt > 0, "ERROR:BUC-020:BUNDLE_DOES_NOT_EXIST"); + require(bundle.state == IBundle.BundleState.Active, "ERROR:BUC-021:BUNDLE_NOT_ACTIVE"); + require(bundle.capital >= bundle.lockedCapital + amount, "ERROR:BUC-022:CAPACITY_TOO_LOW"); bundle.lockedCapital += amount; bundle.updatedAt = block.timestamp; @@ -155,16 +172,16 @@ contract BundleController is { // make sure bundle exists and is not yet closed Bundle storage bundle = _bundles[bundleId]; - require(bundle.createdAt > 0, "ERROR:BUC-001:BUNDLE_DOES_NOT_EXIST"); - require(_activePolicies[bundleId] > 0, "ERROR:BUC-007:NO_ACTIVE_POLICIES_FOR_BUNDLE"); + require(bundle.createdAt > 0, "ERROR:BUC-023:BUNDLE_DOES_NOT_EXIST"); + require(_activePolicies[bundleId] > 0, "ERROR:BUC-024:NO_ACTIVE_POLICIES_FOR_BUNDLE"); collateralAmount = _valueLockedPerPolicy[bundleId][processId]; - require(collateralAmount > 0, "ERROR:BUC-007:NOT_COLLATERALIZED_BY_BUNDLE"); + require(collateralAmount > 0, "ERROR:BUC-025:NOT_COLLATERALIZED_BY_BUNDLE"); // this should never ever fail ... require( bundle.lockedCapital >= collateralAmount, - "PANIC:BUC-008:UNLOCK_CAPITAL_TOO_BIG" + "PANIC:BUC-026:UNLOCK_CAPITAL_TOO_BIG" ); // policy no longer relevant for bundle @@ -185,8 +202,8 @@ contract BundleController is onlyRiskpoolService { Bundle storage bundle = _bundles[bundleId]; - require(bundle.createdAt > 0, "ERROR:BUC-001:BUNDLE_DOES_NOT_EXIST"); - require(bundle.state != IBundle.BundleState.Closed, "ERROR:BUC-005:BUNDLE_CLOSED"); + require(bundle.createdAt > 0, "ERROR:BUC-031:BUNDLE_DOES_NOT_EXIST"); + require(bundle.state != IBundle.BundleState.Closed, "ERROR:BUC-032:BUNDLE_CLOSED"); bundle.balance += amount; bundle.updatedAt = block.timestamp; @@ -198,7 +215,7 @@ contract BundleController is onlyRiskpoolService { Bundle storage bundle = _bundles[bundleId]; - require(bundle.createdAt > 0, "ERROR:BUC-001:BUNDLE_DOES_NOT_EXIST"); + require(bundle.createdAt > 0, "ERROR:BUC-033:BUNDLE_DOES_NOT_EXIST"); revert("NOT_IMPLEMENTED_YET:decreaseBalance(...)"); } @@ -236,7 +253,7 @@ contract BundleController is function getBundle(uint256 bundleId) public view returns(Bundle memory) { Bundle memory bundle = _bundles[bundleId]; - require(bundle.createdAt > 0, "ERROR:BUC-001:BUNDLE_DOES_NOT_EXIST"); + require(bundle.createdAt > 0, "ERROR:BUC-040:BUNDLE_DOES_NOT_EXIST"); return bundle; } @@ -266,17 +283,22 @@ contract BundleController is if (oldState == BundleState.Active) { require( newState == BundleState.Locked || newState == BundleState.Closed, - "ERROR:BUC-013:ACTIVE_INVALID_TRANSITION" + "ERROR:BUC-050:ACTIVE_INVALID_TRANSITION" ); } else if (oldState == BundleState.Locked) { require( newState == BundleState.Active || newState == BundleState.Closed, - "ERROR:BUC-013:LOCKED_INVALID_TRANSITION" + "ERROR:BUC-051:LOCKED_INVALID_TRANSITION" ); } else if (oldState == BundleState.Closed) { - revert("ERROR:BUC-014:CLOSED_IS_FINAL_STATE"); + require( + newState == BundleState.Burned, + "ERROR:BUC-052:CLOSED_INVALID_TRANSITION" + ); + } else if (oldState == BundleState.Burned) { + revert("ERROR:BUC-053:BURNED_IS_FINAL_STATE"); } else { - revert("ERROR:BOC-018:INITIAL_STATE_NOT_HANDLED"); + revert("ERROR:BOC-054:INITIAL_STATE_NOT_HANDLED"); } } diff --git a/contracts/modules/TreasuryModule.sol b/contracts/modules/TreasuryModule.sol index 4f85581..a4a2377 100644 --- a/contracts/modules/TreasuryModule.sol +++ b/contracts/modules/TreasuryModule.sol @@ -234,11 +234,11 @@ contract TreasuryModule is emit LogTreasuryCapitalProcessed(bundle.riskpoolId, bundleId, capitalAmount, success); } - // TODO remove once at ITreasury - event LogTreasuryWithdrawlTransferred(address riskpoolWalletAddress, address to, uint256 amount, bool success); - event LogTreasuryWithdrawlProcessed(uint256 riskpoolId, uint256 bundleId, uint256 amount, bool success); + // // TODO cleanup remove once at ITreasury + // event LogTreasuryWithdrawalTransferred(address riskpoolWalletAddress, address to, uint256 amount, bool success); + // event LogTreasuryWithdrawalProcessed(uint256 riskpoolId, uint256 bundleId, uint256 amount, bool success); - function processWithdrawl(uint256 bundleId, uint256 amount) + function processWithdrawal(uint256 bundleId, uint256 amount) external override returns( bool success, @@ -248,8 +248,9 @@ contract TreasuryModule is // obtain relevant bundle info IBundle.Bundle memory bundle = _bundle.getBundle(bundleId); require( - bundle.capital >= bundle.lockedCapital + amount, - "ERROR:TRS-002:CAPACITY_SMALLER_THAN_WITHDRAWL" + bundle.capital >= bundle.lockedCapital + amount + || (bundle.lockedCapital == 0 && bundle.balance >= amount), + "ERROR:TRS-002:CAPACITY_OR_BALANCE_SMALLER_THAN_WITHDRAWAL" ); // obtain relevant token for product/riskpool pair @@ -260,17 +261,17 @@ contract TreasuryModule is token.allowance( riskpoolWallet, address(this)) >= amount, - "ERROR:TRS-002:ALLOWANCE_SMALLER_THAN_WITHDRAWL" + "ERROR:TRS-002:ALLOWANCE_SMALLER_THAN_WITHDRAWAL" ); - // TODO consider to introduce withdrawl fees + // TODO consider to introduce withdrawal fees netAmount = amount; success = token.transferFrom(riskpoolWallet, bundleOwner, netAmount); - emit LogTreasuryWithdrawlTransferred(riskpoolWallet, bundleOwner, netAmount, success); - require(success, "ERROR:TRS-002:WITHDRAWL_TRANSFER_FAILED"); + emit LogTreasuryWithdrawalTransferred(riskpoolWallet, bundleOwner, netAmount, success); + require(success, "ERROR:TRS-002:WITHDRAWAL_TRANSFER_FAILED"); - emit LogTreasuryWithdrawlProcessed(bundle.riskpoolId, bundleId, netAmount, success); + emit LogTreasuryWithdrawalProcessed(bundle.riskpoolId, bundleId, netAmount, success); } diff --git a/contracts/services/RiskpoolService.sol b/contracts/services/RiskpoolService.sol index a5ae002..fb08f77 100644 --- a/contracts/services/RiskpoolService.sol +++ b/contracts/services/RiskpoolService.sol @@ -72,12 +72,13 @@ contract RiskpoolService is function fundBundle(uint256 bundleId, uint256 amount) external override - onlyOwningRiskpool(bundleId) + onlyOwningRiskpool(bundleId) + returns(bool success, uint256 netAmount) { IBundle.Bundle memory bundle = _bundle.getBundle(bundleId); require(bundle.state != IBundle.BundleState.Closed, "ERROR:RPS-003:BUNDLE_CLOSED"); - (bool success, uint256 netAmount) = _treasury.processCapital(bundleId, amount); + (success, netAmount) = _treasury.processCapital(bundleId, amount); if (success) { _bundle.fund(bundleId, netAmount); } @@ -86,11 +87,15 @@ contract RiskpoolService is function defundBundle(uint256 bundleId, uint256 amount) external override - onlyOwningRiskpool(bundleId) + onlyOwningRiskpool(bundleId) + returns(bool success, uint256 netAmount) { - (bool success, uint256 netAmount) = _treasury.processWithdrawl(bundleId, amount); + (success, netAmount) = _treasury.processWithdrawal(bundleId, amount); + require(success, "ERROR:RPS-004:BUNDLE_DEFUNDING_FAILED"); + require(netAmount == amount, "UUPS"); + if (success) { - _bundle.defund(bundleId, netAmount); + _bundle.defund(bundleId, amount); } } @@ -118,28 +123,29 @@ contract RiskpoolService is _bundle.close(bundleId); } - - function collateralizePolicy(uint256 bundleId, bytes32 processId, uint256 collateralAmount) + function burnBundle(uint256 bundleId) external override onlyOwningRiskpool(bundleId) { - _bundle.collateralizePolicy(bundleId, processId, collateralAmount); - } + // ensure bundle is closed + IBundle.Bundle memory bundle = _bundle.getBundle(bundleId); + require(bundle.state == IBundle.BundleState.Closed, "ERROR:RPS-004:BUNDLE_NOT_CLOSED"); + // withdraw remaining balance + (bool success, uint256 netAmount) = _treasury.processWithdrawal(bundleId, bundle.balance); + require(success, "ERROR:RPS-005:WITHDRAWAL_FAILED"); - function increaseBundleBalance(uint256 bundleId, bytes32 processId, uint256 amount) - external override - onlyOwningRiskpool(bundleId) - { - _bundle.increaseBalance(bundleId, processId, amount); + if (success) { + _bundle.defund(bundleId, bundle.balance); + _bundle.burn(bundleId); + } } - - - function decreaseBundleBalance(uint256 bundleId, bytes32 processId, uint256 amount) + + function collateralizePolicy(uint256 bundleId, bytes32 processId, uint256 collateralAmount) external override onlyOwningRiskpool(bundleId) { - revert("NOT_IMPLEMENTED_YET:decreaseBundleBalance(...)"); + _bundle.collateralizePolicy(bundleId, processId, collateralAmount); } function releasePolicy(uint256 bundleId, bytes32 processId) @@ -157,4 +163,20 @@ contract RiskpoolService is collateralAmount = _bundle.releasePolicy(bundleId, processId); } + + + function increaseBundleBalance(uint256 bundleId, bytes32 processId, uint256 amount) + external override + onlyOwningRiskpool(bundleId) + { + _bundle.increaseBalance(bundleId, processId, amount); + } + + + function decreaseBundleBalance(uint256 bundleId, bytes32 processId, uint256 amount) + external override + onlyOwningRiskpool(bundleId) + { + revert("NOT_IMPLEMENTED_YET:decreaseBundleBalance(...)"); + } } diff --git a/contracts/test/TestProduct.sol b/contracts/test/TestProduct.sol index dc428c0..35d6c62 100644 --- a/contracts/test/TestProduct.sol +++ b/contracts/test/TestProduct.sol @@ -5,6 +5,7 @@ import "@etherisc/gif-interface/contracts/modules/IPolicy.sol"; import "@etherisc/gif-interface/contracts/services/IProductService.sol"; import "@etherisc/gif-interface/contracts/services/IInstanceService.sol"; import "@etherisc/gif-interface/contracts/components/Product.sol"; + import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; contract TestProduct is diff --git a/scripts/setup.py b/scripts/setup.py index 02e81c6..47f02eb 100644 --- a/scripts/setup.py +++ b/scripts/setup.py @@ -4,14 +4,20 @@ def fund_riskpool( instance: GifInstance, owner: Account, + capitalOwner: Account, riskpool, bundleOwner: Account, coin, amount: int ): # transfer funds to riskpool keeper and create allowance - coin.transfer(bundleOwner, amount, {'from': owner}) - coin.approve(instance.getTreasury(), amount, {'from': bundleOwner}) + safetyFactor = 2 + coin.transfer(bundleOwner, safetyFactor * amount, {'from': owner}) + coin.approve(instance.getTreasury(), safetyFactor * amount, {'from': bundleOwner}) + + # create approval for treasury from capital owner to allow for withdrawls + maxUint256 = 2**256-1 + coin.approve(instance.getTreasury(), maxUint256, {'from': capitalOwner}) applicationFilter = bytes(0) riskpool.createBundle( diff --git a/tests/test_apply_underwrite_expire.py b/tests/test_apply_underwrite_expire.py index df8f6fb..c8f216f 100644 --- a/tests/test_apply_underwrite_expire.py +++ b/tests/test_apply_underwrite_expire.py @@ -50,7 +50,7 @@ def test_create_policy( # prepare funded riskpool riskpool = gifTestProduct.getRiskpool().getContract() initialFunding = 10000 - fund_riskpool(instance, owner, riskpool, riskpoolKeeper, testCoin, initialFunding) + fund_riskpool(instance, owner, capitalOwner, riskpool, riskpoolKeeper, testCoin, initialFunding) # check funds after capitalization capitalFees = initialFunding / 20 + 42 @@ -144,12 +144,13 @@ def test_create_expire_and_close_policy( productOwner: Account, riskpoolKeeper: Account, owner: Account, - customer: Account + customer: Account, + capitalOwner: Account ): # prepare funded riskpool riskpool = gifTestProduct.getRiskpool().getContract() initialFunding = 10000 - fund_riskpool(instance, owner, riskpool, riskpoolKeeper, testCoin, initialFunding) + fund_riskpool(instance, owner, capitalOwner, riskpool, riskpoolKeeper, testCoin, initialFunding) # build and use policy application product = gifTestProduct.getContract() @@ -205,12 +206,13 @@ def test_application_with_insufficient_premium_funding( gifTestProduct: GifTestProduct, riskpoolKeeper: Account, owner: Account, - customer: Account + customer: Account, + capitalOwner: Account ): # prepare funded riskpool riskpool = gifTestProduct.getRiskpool().getContract() initialFunding = 10000 - fund_riskpool(instance, owner, riskpool, riskpoolKeeper, testCoin, initialFunding) + fund_riskpool(instance, owner, capitalOwner, riskpool, riskpoolKeeper, testCoin, initialFunding) # build and use policy application product = gifTestProduct.getContract() @@ -288,12 +290,13 @@ def test_riskpool_inactive( gifTestProduct: GifTestProduct, owner: Account, riskpoolKeeper: Account, - customer: Account + customer: Account, + capitalOwner: Account ): # prepare funded riskpool riskpool = gifTestProduct.getRiskpool().getContract() initialFunding = 10000 - fund_riskpool(instance, owner, riskpool, riskpoolKeeper, testCoin, initialFunding) + fund_riskpool(instance, owner, capitalOwner, riskpool, riskpoolKeeper, testCoin, initialFunding) assert riskpool.bundles() == 1 @@ -367,12 +370,13 @@ def test_insufficient_capital( gifTestProduct: GifTestProduct, owner: Account, riskpoolKeeper: Account, - customer: Account + customer: Account, + capitalOwner: Account ): # prepare funded riskpool riskpool = gifTestProduct.getRiskpool().getContract() initialFunding = 50 - fund_riskpool(instance, owner, riskpool, riskpoolKeeper, testCoin, initialFunding) + fund_riskpool(instance, owner, capitalOwner, riskpool, riskpoolKeeper, testCoin, initialFunding) product = gifTestProduct.getContract() diff --git a/tests/test_bundle_create_use_burn.py b/tests/test_bundle_create_use_burn.py index 826f81f..909354f 100644 --- a/tests/test_bundle_create_use_burn.py +++ b/tests/test_bundle_create_use_burn.py @@ -50,7 +50,7 @@ def test_create_bundle( riskpool = gifTestProduct.getRiskpool().getContract() initialFunding = 10000 - fund_riskpool(instance, owner, riskpool, riskpoolKeeper, testCoin, initialFunding) + fund_riskpool(instance, owner, capitalOwner, riskpool, riskpoolKeeper, testCoin, initialFunding) riskpool.bundles() == 1 bundle = riskpool.getBundle(0) @@ -116,7 +116,7 @@ def test_use_bundle( initialFunding = 10000 bundleOwner = riskpoolKeeper - fund_riskpool(instance, owner, riskpool, riskpoolKeeper, testCoin, initialFunding) + fund_riskpool(instance, owner, capitalOwner, riskpool, riskpoolKeeper, testCoin, initialFunding) bundle = _getBundleDict(riskpool, 0) capitalFee = initialFunding / 20 + 42 @@ -173,7 +173,7 @@ def test_use_bundle( assert bundleToken.getBundleId(tokenId) == bundleId -def test_close_bundle( +def test_close_and_burn_bundle( instance: GifInstance, testCoin, gifTestProduct: GifTestProduct, @@ -189,7 +189,7 @@ def test_close_bundle( initialFunding = 10000 bundleOwner = riskpoolKeeper - fund_riskpool(instance, owner, riskpool, bundleOwner, testCoin, initialFunding) + fund_riskpool(instance, owner, capitalOwner, riskpool, bundleOwner, testCoin, initialFunding) premium = 100 sumInsured = 5000 @@ -197,8 +197,8 @@ def test_close_bundle( bundle = _getBundleDict(riskpool, 0) bundleId = bundle['id'] - bundleBalance = bundle['balance'] bundleCapital = bundle['capital'] + bundleBalance = bundle['balance'] product.expire(policyId, {'from': productOwner}) @@ -237,27 +237,87 @@ def test_close_bundle( riskpool.closeBundle(bundleId, {'from': bundleOwner}) bundle = _getBundleDict(riskpool, 0) - assert bundle['state'] == 2 # BundleState { Active, Locked, Closed } + assert bundle['state'] == 2 # BundleState { Active, Locked, Closed, Burned } assert bundle['capital'] == bundleCapital assert bundle['lockedCapital'] == 0 assert bundle['balance'] == bundleBalance - # check that close results in blocking most actions on the bundle - with brownie.reverts('ERROR:BUC-014:CLOSED_IS_FINAL_STATE'): + # check associated nft + bundleToken = instance.getBundleToken() + tokenId = bundle['tokenId'] + + assert bundleToken.exists(tokenId) == True + assert bundleToken.burned(tokenId) == False + assert bundleToken.ownerOf(tokenId) == bundleOwner + assert bundleToken.getBundleId(tokenId) == bundleId + + # check that defunding works even when bundle is closed + riskpoolWalletBefore = testCoin.balanceOf(capitalOwner) + bundleOwnerBefore = testCoin.balanceOf(bundleOwner) + + withdrawalAmount = 999 + tx = riskpool.defundBundle(bundleId, withdrawalAmount, {'from': bundleOwner}) + (success, netWithdrawalAmount) = tx.return_value + + assert success + assert netWithdrawalAmount == withdrawalAmount + + expectedBalance = bundleBalance - netWithdrawalAmount + bundle = _getBundleDict(riskpool, 0) + assert bundle['capital'] == bundleCapital - netWithdrawalAmount + assert bundle['balance'] == expectedBalance + + assert testCoin.balanceOf(capitalOwner) == expectedBalance + assert testCoin.balanceOf(bundleOwner) == bundleOwnerBefore + netWithdrawalAmount + + # check that close results in blocking all other actions on the bundle + with brownie.reverts('ERROR:BUC-052:CLOSED_INVALID_TRANSITION'): riskpool.closeBundle(bundleId, {'from': bundleOwner}) - with brownie.reverts('ERROR:BUC-014:CLOSED_IS_FINAL_STATE'): + with brownie.reverts('ERROR:BUC-052:CLOSED_INVALID_TRANSITION'): riskpool.lockBundle(bundleId, {'from': bundleOwner}) - with brownie.reverts('ERROR:BUC-014:CLOSED_IS_FINAL_STATE'): + with brownie.reverts('ERROR:BUC-052:CLOSED_INVALID_TRANSITION'): riskpool.unlockBundle(bundleId, {'from': bundleOwner}) with brownie.reverts('ERROR:RPS-003:BUNDLE_CLOSED'): fundingAmount = 100000 riskpool.fundBundle(bundleId, fundingAmount, {'from': bundleOwner}) + # attempt to burn bundle with imposter + with brownie.reverts('ERROR:BUC-001:NOT_BUNDLE_OWNER'): + riskpool.burnBundle(bundleId, {'from': customer}) + + assert bundleToken.exists(tokenId) == True + assert bundleToken.burned(tokenId) == False + assert bundleToken.ownerOf(tokenId) == bundleOwner + assert bundleToken.getBundleId(tokenId) == bundleId + + bundle = _getBundleDict(riskpool, 0) + print(bundle) + + # bundle owner buring her/his token + riskpool.burnBundle(bundleId, {'from': bundleOwner}) + + assert bundleToken.exists(tokenId) == True + assert bundleToken.burned(tokenId) == True + assert bundleToken.getBundleId(tokenId) == bundleId + + with brownie.reverts('ERC721: invalid token ID'): + bundleToken.ownerOf(tokenId) == bundleOwner + + bundle = _getBundleDict(riskpool, 0) + assert bundle['capital'] == 0 + assert bundle['lockedCapital'] == 0 + assert bundle['balance'] == 0 + + assert riskpool.getCapital() == 0 + assert riskpool.getTotalValueLocked() == 0 + assert riskpool.getBalance() == 0 + + assert testCoin.balanceOf(capitalOwner) == 0 + -# TODO implement test def test_fund_defund_bundle( instance: GifInstance, testCoin, @@ -269,7 +329,57 @@ def test_fund_defund_bundle( feeOwner: Account, capitalOwner: Account ): - pass + product = gifTestProduct.getContract() + riskpool = gifTestProduct.getRiskpool().getContract() + initialFunding = 10000 + + bundleOwner = riskpoolKeeper + fund_riskpool(instance, owner, capitalOwner, riskpool, bundleOwner, testCoin, initialFunding) + + premium = 100 + sumInsured = 5000 + policyId = apply_for_policy(instance, owner, product, customer, testCoin, premium, sumInsured) + + bundle = _getBundleDict(riskpool, 0) + bundleId = bundle['id'] + bundleCapital = bundle['capital'] + bundleBalance = bundle['balance'] + + assert riskpool.getBalance() == bundleBalance + assert testCoin.balanceOf(capitalOwner) == bundleBalance + + withdrawalAmount = 999 + # (success, netWithdrawlAmount) = riskpool.defundBundle(bundleId, withdrawalAmount, {'from': bundleOwner}) + tx = riskpool.defundBundle(bundleId, withdrawalAmount, {'from': bundleOwner}) + (success, netWithdrawlAmount) = tx.return_value + + assert success + assert netWithdrawlAmount == withdrawalAmount + + bundle = _getBundleDict(riskpool, 0) + expectedCapital = bundleCapital - netWithdrawlAmount + expectedBalance = bundleBalance - netWithdrawlAmount + assert bundle['capital'] == expectedCapital + assert bundle['balance'] == expectedBalance + assert riskpool.getCapital() == expectedCapital + assert riskpool.getBalance() == expectedBalance + assert testCoin.balanceOf(capitalOwner) == expectedBalance + + fundingAmount = 2000 + tx = riskpool.fundBundle(bundleId, fundingAmount, {'from': bundleOwner}) + (success, netFundingAmount) = tx.return_value + + assert success + assert netFundingAmount == fundingAmount - (fundingAmount / 20 + 42) + + bundle = _getBundleDict(riskpool, 0) + expectedCapital = bundleCapital - netWithdrawlAmount + netFundingAmount + expectedBalance = bundleBalance - netWithdrawlAmount + netFundingAmount + assert bundle['capital'] == expectedCapital + assert bundle['balance'] == expectedBalance + assert riskpool.getCapital() == expectedCapital + assert riskpool.getBalance() == expectedBalance + assert testCoin.balanceOf(capitalOwner) == expectedBalance def _getApplicationDict(instance, policyId): diff --git a/tests/test_deploy_instance.py b/tests/test_deploy_instance.py index 9b01ee3..47de44a 100644 --- a/tests/test_deploy_instance.py +++ b/tests/test_deploy_instance.py @@ -58,7 +58,7 @@ def test_Bundle(instance: GifInstance, owner): assert bundle.bundles() == 0 - with brownie.reverts('ERROR:BUC-001:BUNDLE_DOES_NOT_EXIST'): + with brownie.reverts('ERROR:BUC-040:BUNDLE_DOES_NOT_EXIST'): bundle.getBundle(0) with pytest.raises(AttributeError): diff --git a/tests/test_submit_claim.py b/tests/test_submit_claim.py index 5b45382..1713b17 100644 --- a/tests/test_submit_claim.py +++ b/tests/test_submit_claim.py @@ -43,12 +43,13 @@ def test_claim_submission( owner: Account, customer: Account, productOwner: Account, - riskpoolKeeper: Account + riskpoolKeeper: Account, + capitalOwner: Account ): # prepare funded riskpool riskpool = gifTestProduct.getRiskpool().getContract() initialFunding = 10000 - fund_riskpool(instance, owner, riskpool, riskpoolKeeper, testCoin, initialFunding) + fund_riskpool(instance, owner, capitalOwner, riskpool, riskpoolKeeper, testCoin, initialFunding) # build and use policy application product = gifTestProduct.getContract() @@ -89,12 +90,13 @@ def test_claim_submission_for_expired_policy( owner: Account, customer: Account, productOwner: Account, - riskpoolKeeper: Account + riskpoolKeeper: Account, + capitalOwner: Account ): # prepare funded riskpool riskpool = gifTestProduct.getRiskpool().getContract() initialFunding = 10000 - fund_riskpool(instance, owner, riskpool, riskpoolKeeper, testCoin, initialFunding) + fund_riskpool(instance, owner, capitalOwner, riskpool, riskpoolKeeper, testCoin, initialFunding) # build and use policy application product = gifTestProduct.getContract() @@ -120,12 +122,13 @@ def test_multiple_claim_submission( owner: Account, customer: Account, productOwner: Account, - riskpoolKeeper: Account + riskpoolKeeper: Account, + capitalOwner: Account ): # prepare funded riskpool riskpool = gifTestProduct.getRiskpool().getContract() initialFunding = 20000 - fund_riskpool(instance, owner, riskpool, riskpoolKeeper, testCoin, initialFunding) + fund_riskpool(instance, owner, capitalOwner, riskpool, riskpoolKeeper, testCoin, initialFunding) # build and use policy application product = gifTestProduct.getContract()