From 967c2adaa38aea7366347f1a78d64de1e36fdd2a Mon Sep 17 00:00:00 2001 From: Matthias Zimmermann Date: Fri, 16 Sep 2022 14:10:53 +0000 Subject: [PATCH 1/5] intermediate state, 2 tests failing --- contracts/examples/AyiiProduct.sol | 66 +++++-- contracts/modules/BundleController.sol | 22 ++- contracts/modules/PoolController.sol | 11 +- tests/test_ayii_product_process_policies.py | 197 +++++++++++++++++++- 4 files changed, 270 insertions(+), 26 deletions(-) diff --git a/contracts/examples/AyiiProduct.sol b/contracts/examples/AyiiProduct.sol index e4bd562..78cbfb1 100644 --- a/contracts/examples/AyiiProduct.sol +++ b/contracts/examples/AyiiProduct.sol @@ -395,35 +395,77 @@ contract AyiiProduct is function processPoliciesForRisk(bytes32 riskId, uint256 batchSize) external + onlyRole(INSURER_ROLE) returns(bytes32 [] memory processedPolicies) { Risk memory risk = _risks[riskId]; require(risk.responseAt > 0, "ERROR:AYI-030:ORACLE_RESPONSE_MISSING"); - EnumerableSet.Bytes32Set storage policyIds = _policies[riskId]; - uint256 elements = EnumerableSet.length(policyIds); + uint256 elements = EnumerableSet.length(_policies[riskId]); + if (elements == 0) { + emit LogAyiiRiskProcessed(riskId, 0); + return new bytes32[](0); + } if (batchSize == 0) { batchSize = elements; } - else { batchSize = min(batchSize, elements); } + else { batchSize = min(batchSize, elements); } processedPolicies = new bytes32[](batchSize); + uint256 elementIdx = elements - 1; + for (uint256 i = 0; i < batchSize; i++) { // grab and process the last policy - bytes32 policyId = EnumerableSet.at(policyIds, EnumerableSet.length(policyIds) - 1); - _processPolicy(policyId, risk); - - _expire(policyId); - _close(policyId); - + bytes32 policyId = EnumerableSet.at(_policies[riskId], elementIdx - i); + processPolicy(riskId, policyId); processedPolicies[i] = policyId; - - // remove the last (processed) policy from the list - EnumerableSet.remove(policyIds, policyId); } emit LogAyiiRiskProcessed(riskId, batchSize); } +<<<<<<< HEAD +======= + function processPolicy(bytes32 riskId, bytes32 policyId) + public + onlyRole(INSURER_ROLE) + { + Risk memory risk = _risks[riskId]; + require(risk.responseAt > 0, "ERROR:AYI-030:ORACLE_RESPONSE_MISSING"); + + require(EnumerableSet.contains(_policies[riskId], policyId), "ERROR:AYI-031:POLICY_FOR_RISK_UNKNOWN"); + EnumerableSet.remove(_policies[riskId], policyId); + + IPolicy.Application memory application + = _getApplication(policyId); + + uint256 claimAmount = calculatePayout( + risk.payoutPercentage, + application.sumInsuredAmount); + + uint256 claimId = _newClaim(policyId, claimAmount, ""); + emit LogAyiiClaimCreated(policyId, claimId, claimAmount); + + if (claimAmount > 0) { + uint256 payoutAmount = claimAmount; + _confirmClaim(policyId, claimId, payoutAmount); + + uint256 payoutId = _newPayout(policyId, claimId, payoutAmount, ""); + _processPayout(policyId, payoutId); + + emit LogAyiiPayoutCreated(policyId, payoutAmount); + } + else { + _declineClaim(policyId, claimId); + _closeClaim(policyId, claimId); + } + + _expire(policyId); + _close(policyId); + + emit LogAyiiPolicyProcessed(policyId); + } + +>>>>>>> 7bf9cc4 (intermediate state, 2 tests failing) function calculatePayout(uint256 payoutPercentage, uint256 sumInsuredAmount) public pure diff --git a/contracts/modules/BundleController.sol b/contracts/modules/BundleController.sol index d83c812..def79b5 100644 --- a/contracts/modules/BundleController.sol +++ b/contracts/modules/BundleController.sol @@ -185,19 +185,27 @@ contract BundleController is function releasePolicy(uint256 bundleId, bytes32 processId) external override onlyRiskpoolService - returns(uint256 collateralAmount) + returns(uint256 remainingCollateralAmount) { + IPolicy.Policy memory policy = _policy.getPolicy(processId); + require( + policy.state == IPolicy.PolicyState.Closed, + "ERROR:POL-025:POLICY_STATE_INVALID" + ); + // make sure bundle exists and is not yet closed Bundle storage bundle = _bundles[bundleId]; require(bundle.createdAt > 0, "ERROR:BUC-024:BUNDLE_DOES_NOT_EXIST"); require(_activePolicies[bundleId] > 0, "ERROR:BUC-025:NO_ACTIVE_POLICIES_FOR_BUNDLE"); - collateralAmount = _valueLockedPerPolicy[bundleId][processId]; - require(collateralAmount > 0, "ERROR:BUC-026:NOT_COLLATERALIZED_BY_BUNDLE"); + uint256 lockedByBundleAmount = _valueLockedPerPolicy[bundleId][processId]; + require(lockedByBundleAmount > 0, "ERROR:BUC-026:NOT_COLLATERALIZED_BY_BUNDLE"); + + remainingCollateralAmount = lockedByBundleAmount - policy.payoutAmount; // this should never ever fail ... require( - bundle.lockedCapital >= collateralAmount, + bundle.lockedCapital >= remainingCollateralAmount, "PANIC:BUC-027:UNLOCK_CAPITAL_TOO_BIG" ); @@ -206,11 +214,11 @@ contract BundleController is delete _valueLockedPerPolicy[bundleId][processId]; // update bundle capital - bundle.lockedCapital -= collateralAmount; - bundle.updatedAt = block.timestamp; + bundle.lockedCapital -= remainingCollateralAmount; + bundle.updatedAt = block.timestamp; // solhint-disable-line uint256 capacityAmount = bundle.capital - bundle.lockedCapital; - emit LogBundlePolicyExpired(bundleId, processId, collateralAmount, capacityAmount); + emit LogBundlePolicyExpired(bundleId, processId, remainingCollateralAmount, capacityAmount); } diff --git a/contracts/modules/PoolController.sol b/contracts/modules/PoolController.sol index 4cf48fa..8b62fcf 100644 --- a/contracts/modules/PoolController.sol +++ b/contracts/modules/PoolController.sol @@ -233,18 +233,19 @@ contract PoolController is IRiskpool riskpool = _getRiskpoolComponent(metadata); riskpool.releasePolicy(processId); - uint256 riskpoolId = _riskpoolIdForProductId[metadata.productId]; IPolicy.Application memory application = _policy.getApplication(processId); + + uint256 riskpoolId = _riskpoolIdForProductId[metadata.productId]; IPool.Pool storage pool = _riskpools[riskpoolId]; - uint256 collateralAmount = _collateralAmount[processId]; + uint256 remainingCollateralAmount = _collateralAmount[processId] - policy.payoutAmount; pool.sumOfSumInsuredAtRisk -= application.sumInsuredAmount; - pool.lockedCapital -= collateralAmount; - pool.updatedAt = block.timestamp; + pool.lockedCapital -= remainingCollateralAmount; + pool.updatedAt = block.timestamp; // solhint-disable-line // free memory delete _collateralAmount[processId]; - emit LogRiskpoolCollateralReleased(riskpoolId, processId, collateralAmount); + emit LogRiskpoolCollateralReleased(riskpoolId, processId, remainingCollateralAmount); } diff --git a/tests/test_ayii_product_process_policies.py b/tests/test_ayii_product_process_policies.py index c4db57b..f34bfc0 100644 --- a/tests/test_ayii_product_process_policies.py +++ b/tests/test_ayii_product_process_policies.py @@ -249,10 +249,203 @@ def test_process_policies_for_risk( assert processedPolicyIds[0] == policyId[2] assert processedPolicyIds[1] == policyId[1] - # and finally another 2 policies - BUT only one remains to be actually processed + # another 2 policies - BUT only one remains to be actually processed tx = product.processPoliciesForRisk(riskId[0], 2, {'from': insurer}) processedPolicyIds = tx.return_value assert len(processedPolicyIds) == 1 assert processedPolicyIds[0] == policyId[0] - \ No newline at end of file + + # and finally another 2 policies - BUT none remains to be actually processed + tx = product.processPoliciesForRisk(riskId[0], 2, {'from': insurer}) + processedPolicyIds = tx.return_value + + assert len(processedPolicyIds) == 0 + + +def test_process_policies_mix_batch_individual_processing( + instance: GifInstance, + instanceOperator, + gifAyiiProduct: GifAyiiProduct, + riskpoolWallet, + investor, + insurer, + customer, +): + instanceService = instance.getInstanceService() + + product = gifAyiiProduct.getContract() + oracle = gifAyiiProduct.getOracle().getContract() + riskpool = gifAyiiProduct.getRiskpool().getContract() + + clOperator = gifAyiiProduct.getOracle().getClOperator() + + print('--- test setup funding riskpool --------------------------') + + token = gifAyiiProduct.getToken() + + riskpoolFunding = 200000 + fund_riskpool( + instance, + instanceOperator, + riskpoolWallet, + riskpool, + investor, + token, + riskpoolFunding) + + # check riskpool funds and book keeping after funding + riskpoolBalanceAfterFunding = token.balanceOf(riskpoolWallet) + riskpoolExpectedBalance = 0.95 * riskpoolFunding - 42 + + # check risk bundle in riskpool and book keeping after funding + bundleIdx = 0 + bundleAfterFunding = riskpool.getBundle(bundleIdx).dict() + bundleId = bundleAfterFunding['id'] + + # cheeck bundle token (nft) + bundleNftId = bundleAfterFunding['tokenId'] + bundleToken = contractFromAddress(BundleToken, instanceService.getBundleToken()) + + print('--- test setup risks -------------------------------------') + + projectId = s2b32('2022.kenya.wfp.ayii') + uaiId = [s2b32('1234'), s2b32('2345')] + cropId = s2b32('mixed') + + triggerFloat = 0.75 + exitFloat = 0.1 + tsiFloat = 0.9 + aphFloat = [2.0, 1.8] + + multiplier = product.getPercentageMultiplier() + trigger = multiplier * triggerFloat + exit = multiplier * exitFloat + tsi = multiplier * tsiFloat + aph = [multiplier * aphFloat[0], multiplier * aphFloat[1]] + + tx = [None, None, None, None, None] + tx[0] = product.createRisk(projectId, uaiId[0], cropId, trigger, exit, tsi, aph[0], {'from': insurer}) + + riskId = [None, None, None, None, None] + riskId = [tx[0].return_value] + print('riskId {}'.format(riskId)) + assert riskId[0] == product.getRiskId(projectId, uaiId[0], cropId) + + + print('--- test setup funding customers -------------------------') + + assert token.balanceOf(customer) == 0 + + customerFunding = 5000 + fund_customer(instance, instanceOperator, customer, token, customerFunding) + + print('--- test create policies ---------------------------------') + + premium = [300] + sumInsured = [2000] + + tx[0] = product.applyForPolicy(customer, premium[0], sumInsured[0], riskId[0], {'from': insurer}) + tx[1] = product.applyForPolicy(customer, premium[0], sumInsured[0], riskId[0], {'from': insurer}) + tx[2] = product.applyForPolicy(customer, premium[0], sumInsured[0], riskId[0], {'from': insurer}) + tx[3] = product.applyForPolicy(customer, premium[0], sumInsured[0], riskId[0], {'from': insurer}) + tx[4] = product.applyForPolicy(customer, premium[0], sumInsured[0], riskId[0], {'from': insurer}) + + policyId = [None, None, None, None, None] + policyId = [tx[0].return_value, tx[1].return_value, tx[2].return_value, tx[3].return_value, tx[4].return_value] + print('policyId {}'.format(policyId)) + + print('--- step trigger oracle (call chainlin node) -------------') + + tx[0] = product.triggerOracle(policyId[0], {'from': insurer}) + requestId = [tx[0].return_value] + + # check event attributes + clRequestEvent = tx[0].events['OracleRequest'][0] + print('chainlink requestEvent {}'.format(clRequestEvent)) + + requestEvent = tx[0].events['LogAyiiRiskDataRequested'][0] + print('ayii requestEvent {}'.format(requestEvent)) + + + print('--- step test oracle response ----------------------------') + + risk = product.getRisk(riskId[0]).dict() + + # create aaay data for oracle response + # aaay value selected triggers a payout + aaayFloat = 1.1 + aaay = product.getPercentageMultiplier() * aaayFloat + + data = [None, None] + data[0] = oracle.encodeFulfillParameters( + clRequestEvent['requestId'], + projectId, + uaiId[0], + cropId, + aaay + ) + + # simulate callback from oracle node with call to chainlink operator contract + tx[0] = clOperator.fulfillOracleRequest2( + clRequestEvent['requestId'], + clRequestEvent['payment'], + clRequestEvent['callbackAddr'], + clRequestEvent['callbackFunctionId'], + clRequestEvent['cancelExpiration'], + data[0] + ) + + print(tx[0].info()) + + receivedEvent = tx[0].events['LogAyiiRiskDataReceived'][0] + print('ayii requestEvent {}'.format(receivedEvent)) + + # verify in risk that aaay data properly arrives in ayii product cotract + risk = product.getRisk(riskId[0]).dict() + print('risk {}'.format(risk)) + + + print('--- step test process policies (risk[0]) -----------------') + + print('balanceOf(riskpoolWallet): {}'.format(token.balanceOf(riskpoolWallet))) + print('sumInsured[0]: {}'.format(sumInsured[0])) + + # try to trigger without insurer role + with brownie.reverts('AccessControl: account 0x5aeda56215b167893e80b4fe645ba6d5bab767de is missing role 0xf098b7742e998f92a3c749f35e64ef555edcecec4b78a00c532a4f385915955b'): + product.processPolicy(riskId[0], policyId[3], {'from': customer}) + + tx = product.processPolicy(riskId[0], policyId[3], {'from': insurer}) + print(tx.info()) + + assert False + + # claim processing for policies associated with the specified risk + # batch size=2 triggers processing of 2 policies for this risk + tx = product.processPoliciesForRisk(riskId[0], 2, {'from': insurer}) + processedPolicyIds = tx.return_value + + assert len(processedPolicyIds) == 2 + assert processedPolicyIds[0] == policyId[4] + assert processedPolicyIds[1] == policyId[3] + + # process another 2 policies + tx = product.processPoliciesForRisk(riskId[0], 2, {'from': insurer}) + processedPolicyIds = tx.return_value + + assert len(processedPolicyIds) == 2 + assert processedPolicyIds[0] == policyId[2] + assert processedPolicyIds[1] == policyId[1] + + # another 2 policies - BUT only one remains to be actually processed + tx = product.processPoliciesForRisk(riskId[0], 2, {'from': insurer}) + processedPolicyIds = tx.return_value + + assert len(processedPolicyIds) == 1 + assert processedPolicyIds[0] == policyId[0] + + # and finally another 2 policies - BUT none remains to be actually processed + tx = product.processPoliciesForRisk(riskId[0], 2, {'from': insurer}) + processedPolicyIds = tx.return_value + + assert len(processedPolicyIds) == 0 From a02dd456a54822e7c3886f88228140be1257ebc7 Mon Sep 17 00:00:00 2001 From: Matthias Zimmermann Date: Fri, 16 Sep 2022 21:06:10 +0000 Subject: [PATCH 2/5] add processPayout to pool, bundle, service --- .vscode/settings.json | 2 +- brownie-config.yaml | 4 +- contracts/examples/AyiiProduct.sol | 17 +++--- contracts/flows/PolicyDefaultFlow.sol | 2 +- contracts/modules/BundleController.sol | 49 +++++++++++++---- contracts/modules/PoolController.sol | 22 ++++++++ contracts/services/RiskpoolService.sol | 7 +++ contracts/test/TestCoin.sol | 1 + tests/test_ayii_product.py | 60 ++++++++++++++------- tests/test_ayii_product_process_policies.py | 46 ++++++++-------- 10 files changed, 147 insertions(+), 63 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index dc3310b..9167aba 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -9,7 +9,7 @@ "solidity.remappingsUnix": [ "@openzeppelin/=/home/vscode/.brownie/packages/OpenZeppelin/openzeppelin-contracts@4.7.3", "@chainlink/=/home/vscode/.brownie/packages/smartcontractkit/chainlink@1.6.0", - "@etherisc/gif-interface/=/home/vscode/.brownie/packages/etherisc/gif-interface@3f16cfe", + "@etherisc/gif-interface/=/home/vscode/.brownie/packages/etherisc/gif-interface@fb9bc39", ], "solidity.compileUsingRemoteVersion": "v0.8.2+commit.661d1103", "peacock.remoteColor": "1D3C43", diff --git a/brownie-config.yaml b/brownie-config.yaml index 72ff872..6bd640e 100644 --- a/brownie-config.yaml +++ b/brownie-config.yaml @@ -22,7 +22,7 @@ compiler: remappings: - "@openzeppelin=OpenZeppelin/openzeppelin-contracts@4.7.3" - "@chainlink=smartcontractkit/chainlink@1.6.0" - - "@etherisc/gif-interface=etherisc/gif-interface@3f16cfe" + - "@etherisc/gif-interface=etherisc/gif-interface@fb9bc39" # packages below will be added to brownie # you may use 'brownie pm list' after 'brownie compile' @@ -32,7 +32,7 @@ dependencies: # github dependency format: /@ - OpenZeppelin/openzeppelin-contracts@4.7.3 - smartcontractkit/chainlink@1.6.0 - - etherisc/gif-interface@3f16cfe + - etherisc/gif-interface@fb9bc39 # exclude open zeppeling contracts when calculating test coverage # https://eth-brownie.readthedocs.io/en/v1.10.3/config.html#exclude_paths diff --git a/contracts/examples/AyiiProduct.sol b/contracts/examples/AyiiProduct.sol index 78cbfb1..a5dd857 100644 --- a/contracts/examples/AyiiProduct.sol +++ b/contracts/examples/AyiiProduct.sol @@ -416,27 +416,27 @@ contract AyiiProduct is for (uint256 i = 0; i < batchSize; i++) { // grab and process the last policy bytes32 policyId = EnumerableSet.at(_policies[riskId], elementIdx - i); - processPolicy(riskId, policyId); + processPolicy(policyId); processedPolicies[i] = policyId; } emit LogAyiiRiskProcessed(riskId, batchSize); } -<<<<<<< HEAD -======= - function processPolicy(bytes32 riskId, bytes32 policyId) + function processPolicy(bytes32 policyId) public onlyRole(INSURER_ROLE) { + IPolicy.Application memory application = _getApplication(policyId); + bytes32 riskId = abi.decode(application.data, (bytes32)); Risk memory risk = _risks[riskId]; - require(risk.responseAt > 0, "ERROR:AYI-030:ORACLE_RESPONSE_MISSING"); - require(EnumerableSet.contains(_policies[riskId], policyId), "ERROR:AYI-031:POLICY_FOR_RISK_UNKNOWN"); + require(risk.id == riskId, "ERROR:AYI-030:RISK_ID_INVALID"); + require(risk.responseAt > 0, "ERROR:AYI-031:ORACLE_RESPONSE_MISSING"); + require(EnumerableSet.contains(_policies[riskId], policyId), "ERROR:AYI-032:POLICY_FOR_RISK_UNKNOWN"); + EnumerableSet.remove(_policies[riskId], policyId); - IPolicy.Application memory application - = _getApplication(policyId); uint256 claimAmount = calculatePayout( risk.payoutPercentage, @@ -465,7 +465,6 @@ contract AyiiProduct is emit LogAyiiPolicyProcessed(policyId); } ->>>>>>> 7bf9cc4 (intermediate state, 2 tests failing) function calculatePayout(uint256 payoutPercentage, uint256 sumInsuredAmount) public pure diff --git a/contracts/flows/PolicyDefaultFlow.sol b/contracts/flows/PolicyDefaultFlow.sol index 03325ed..b784e29 100644 --- a/contracts/flows/PolicyDefaultFlow.sol +++ b/contracts/flows/PolicyDefaultFlow.sol @@ -272,7 +272,7 @@ contract PolicyDefaultFlow is policy.processPayout(processId, payoutId); PoolController pool = getPoolContract(); - pool.decreaseBalance(processId, netPayoutAmount + feeAmount); + pool.processPayout(processId, netPayoutAmount + feeAmount); } function request( diff --git a/contracts/modules/BundleController.sol b/contracts/modules/BundleController.sol index def79b5..4e5f83d 100644 --- a/contracts/modules/BundleController.sol +++ b/contracts/modules/BundleController.sol @@ -182,6 +182,41 @@ contract BundleController is } + function processPayout(uint256 bundleId, bytes32 processId, uint256 amount) + external override + onlyRiskpoolService + { + IPolicy.Policy memory policy = _policy.getPolicy(processId); + require( + policy.state != IPolicy.PolicyState.Closed, + "ERROR:POL-030:POLICY_STATE_INVALID" + ); + + // check there are policies and there is sufficient locked capital for policy + require(_activePolicies[bundleId] > 0, "ERROR:BUC-031:NO_ACTIVE_POLICIES_FOR_BUNDLE"); + require(_valueLockedPerPolicy[bundleId][processId] >= amount, "ERROR:BUC-032:COLLATERAL_INSUFFICIENT_FOR_POLICY"); + + // make sure bundle exists and is not yet closed + Bundle storage bundle = _bundles[bundleId]; + require(bundle.createdAt > 0, "ERROR:BUC-033:BUNDLE_DOES_NOT_EXIST"); + require( + bundle.state == IBundle.BundleState.Active + || bundle.state == IBundle.BundleState.Locked, + "ERROR:BUC-034:BUNDLE_STATE_INVALID"); + require(bundle.capital >= amount, "ERROR:BUC-035:CAPITAL_TOO_LOW"); + require(bundle.lockedCapital >= amount, "ERROR:BUC-036:LOCKED_CAPITAL_TOO_LOW"); + require(bundle.balance >= amount, "ERROR:BUC-037:BALANCE_TOO_LOW"); + + _valueLockedPerPolicy[bundleId][processId] -= amount; + bundle.capital -= amount; + bundle.lockedCapital -= amount; + bundle.balance -= amount; + bundle.updatedAt = block.timestamp; // solhint-disable-line + + emit LogBundlePayoutProcessed(bundleId, processId, amount); + } + + function releasePolicy(uint256 bundleId, bytes32 processId) external override onlyRiskpoolService @@ -198,14 +233,10 @@ contract BundleController is require(bundle.createdAt > 0, "ERROR:BUC-024:BUNDLE_DOES_NOT_EXIST"); require(_activePolicies[bundleId] > 0, "ERROR:BUC-025:NO_ACTIVE_POLICIES_FOR_BUNDLE"); - uint256 lockedByBundleAmount = _valueLockedPerPolicy[bundleId][processId]; - require(lockedByBundleAmount > 0, "ERROR:BUC-026:NOT_COLLATERALIZED_BY_BUNDLE"); - - remainingCollateralAmount = lockedByBundleAmount - policy.payoutAmount; - + uint256 lockedForPolicyAmount = _valueLockedPerPolicy[bundleId][processId]; // this should never ever fail ... require( - bundle.lockedCapital >= remainingCollateralAmount, + bundle.lockedCapital >= lockedForPolicyAmount, "PANIC:BUC-027:UNLOCK_CAPITAL_TOO_BIG" ); @@ -214,11 +245,11 @@ contract BundleController is delete _valueLockedPerPolicy[bundleId][processId]; // update bundle capital - bundle.lockedCapital -= remainingCollateralAmount; + bundle.lockedCapital -= lockedForPolicyAmount; bundle.updatedAt = block.timestamp; // solhint-disable-line uint256 capacityAmount = bundle.capital - bundle.lockedCapital; - emit LogBundlePolicyExpired(bundleId, processId, remainingCollateralAmount, capacityAmount); + emit LogBundlePolicyReleased(bundleId, processId, lockedForPolicyAmount, capacityAmount); } @@ -229,7 +260,7 @@ contract BundleController is { Bundle storage bundle = _bundles[bundleId]; bundle.balance += amount; - bundle.updatedAt = block.timestamp; + bundle.updatedAt = block.timestamp; // solhint-disable-line } diff --git a/contracts/modules/PoolController.sol b/contracts/modules/PoolController.sol index 8b62fcf..739244d 100644 --- a/contracts/modules/PoolController.sol +++ b/contracts/modules/PoolController.sol @@ -249,6 +249,28 @@ contract PoolController is } + function processPayout(bytes32 processId, uint256 amount) + external override + onlyPolicyFlow("Pool") + { + IPolicy.Metadata memory metadata = _policy.getMetadata(processId); + uint256 riskpoolId = _riskpoolIdForProductId[metadata.productId]; + IPool.Pool storage pool = _riskpools[riskpoolId]; + require(pool.createdAt > 0, "ERROR:POL-026:RISKPOOL_ID_INVALID"); + require(pool.capital >= amount, "ERROR:POL-027:CAPITAL_TOO_LOW"); + require(pool.lockedCapital >= amount, "ERROR:POL-028:LOCKED_CAPITAL_TOO_LOW"); + require(pool.balance >= amount, "ERROR:POL-029:BALANCE_TOO_LOW"); + + pool.capital -= amount; + pool.lockedCapital -= amount; + pool.balance -= amount; + pool.updatedAt = block.timestamp; // solhint-disable-line + + IRiskpool riskpool = _getRiskpoolComponent(metadata); + riskpool.processPolicyPayout(processId, amount); + } + + function increaseBalance(bytes32 processId, uint256 amount) external override onlyPolicyFlow("Pool") diff --git a/contracts/services/RiskpoolService.sol b/contracts/services/RiskpoolService.sol index 654cb72..18d2f8b 100644 --- a/contracts/services/RiskpoolService.sol +++ b/contracts/services/RiskpoolService.sol @@ -233,6 +233,13 @@ contract RiskpoolService is _bundle.collateralizePolicy(bundleId, processId, collateralAmount); } + function processPayout(uint256 bundleId, bytes32 processId, uint256 amount) + external override + onlyOwningRiskpool(bundleId, true) + { + _bundle.processPayout(bundleId, processId, amount); + } + function releasePolicy(uint256 bundleId, bytes32 processId) external override onlyOwningRiskpool(bundleId, false) diff --git a/contracts/test/TestCoin.sol b/contracts/test/TestCoin.sol index 449f2ca..460d58f 100644 --- a/contracts/test/TestCoin.sol +++ b/contracts/test/TestCoin.sol @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: Apache-2.0 pragma solidity 0.8.2; import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; diff --git a/tests/test_ayii_product.py b/tests/test_ayii_product.py index 9661d07..c5199fe 100644 --- a/tests/test_ayii_product.py +++ b/tests/test_ayii_product.py @@ -159,13 +159,17 @@ def test_happy_path( assert riskpoolBalanceAfterPremiums == riskpoolBalanceAfterFunding + netPremium[0] + netPremium[1] # check risk bundle after premium + riskpoolExpectedCapital = riskpoolExpectedBalance + riskpoolExpectedLockedCapital = sumInsured[0] + sumInsured[1] + riskpoolExpectedBalance += netPremium[0] + netPremium[1] + bundleAfterPremium = riskpool.getBundle(bundleIdx).dict() assert bundleAfterPremium['id'] == 1 assert bundleAfterPremium['riskpoolId'] == riskpool.getId() assert bundleAfterPremium['state'] == 0 - assert bundleAfterPremium['capital'] == riskpoolExpectedBalance - assert bundleAfterPremium['lockedCapital'] == sumInsured[0] + sumInsured[1] - assert bundleAfterPremium['balance'] == riskpoolExpectedBalance + netPremium[0] + netPremium[1] + assert bundleAfterPremium['capital'] == riskpoolExpectedCapital + assert bundleAfterPremium['lockedCapital'] == riskpoolExpectedLockedCapital + assert bundleAfterPremium['balance'] == riskpoolExpectedBalance policyId = [None, None] policyId = [tx[0].return_value, tx[1].return_value] @@ -365,6 +369,16 @@ def test_happy_path( assert expectedPayoutAmount > 0 assert expectedPayoutAmount <= sumInsured[0] + policy = instanceService.getPolicy(policyId[0]).dict() + print('policy {}'.format(policy)) + assert policy['state'] == 2 # enum PolicyState {Active, Expired, Closed} + assert policy['claimsCount'] == 1 + assert policy['openClaimsCount'] == 0 + assert policy['payoutMaxAmount'] == sumInsured[0] + assert policy['payoutAmount'] == expectedPayoutAmount + assert policy['createdAt'] > 0 + assert policy['updatedAt'] >= policy['createdAt'] + claim = instanceService.getClaim(policyId[0], 0).dict() print('claim {}'.format(claim)) assert claim['state'] == 3 # ClaimState {Applied, Confirmed, Declined, Closed} @@ -392,24 +406,23 @@ def test_happy_path( assert token.balanceOf(customer) == customerBalanceAfterPremium + expectedPayoutAmount assert token.balanceOf(customer2) == customer2BalanceAfterPremium + riskpoolExpectedCapital -= expectedPayoutAmount + riskpoolExpectedLockedCapital = sumInsured[1] + riskpoolExpectedBalance -= expectedPayoutAmount + # check risk bundle after payout bundleAfterPayout = riskpool.getBundle(bundleIdx).dict() assert bundleAfterPayout['id'] == 1 assert bundleAfterPayout['riskpoolId'] == riskpool.getId() assert bundleAfterPayout['state'] == 0 - assert bundleAfterPayout['capital'] == riskpoolExpectedBalance - assert bundleAfterPayout['lockedCapital'] == sumInsured[1] - assert bundleAfterPayout['balance'] == riskpoolExpectedBalance + netPremium[0] + netPremium[1] - expectedPayoutAmount - - # record riskpool state after processing - balanceAfterProcessing = riskpool.getBalance() - valueLockedAfterProcessing = riskpool.getTotalValueLocked() - capacityAfterProcessing = riskpool.getCapacity() + assert bundleAfterPayout['capital'] == riskpoolExpectedCapital + assert bundleAfterPayout['lockedCapital'] == riskpoolExpectedLockedCapital + assert bundleAfterPayout['balance'] == riskpoolExpectedBalance # check book keeping on riskpool level - assert valueLockedAfterProcessing == valueLockedBeforeProcessing - sumInsured[0] - assert capacityAfterProcessing == capacityBeforeProcessing + sumInsured[0] - assert balanceAfterProcessing == balanceBeforeProcessing - expectedPayoutAmount + assert riskpool.getCapital() == riskpoolExpectedCapital + assert riskpool.getTotalValueLocked() == riskpoolExpectedLockedCapital + assert riskpool.getBalance() == riskpoolExpectedBalance print('--- step test process policies (risk[1]) -----------------') @@ -433,14 +446,17 @@ def test_happy_path( assert claim['claimAmount'] == 0 # check bundle state + riskpoolExpectedLockedCapital = 0 bundleAfter2ndPayout = riskpool.getBundle(bundleIdx).dict() - assert bundleAfter2ndPayout['capital'] == riskpoolExpectedBalance - assert bundleAfter2ndPayout['lockedCapital'] == 0 - assert bundleAfter2ndPayout['balance'] == riskpoolExpectedBalance + netPremium[0] + netPremium[1] - expectedPayoutAmount + + assert bundleAfter2ndPayout['capital'] == riskpoolExpectedCapital + assert bundleAfter2ndPayout['lockedCapital'] == riskpoolExpectedLockedCapital + assert bundleAfter2ndPayout['balance'] == riskpoolExpectedBalance # check riskpool state - assert riskpool.getTotalValueLocked() == 0 - assert riskpool.getBalance() == bundleAfter2ndPayout['balance'] + assert riskpool.getCapital() == riskpoolExpectedCapital + assert riskpool.getTotalValueLocked() == riskpoolExpectedLockedCapital + assert riskpool.getBalance() == riskpoolExpectedBalance print('--- step test close bundle -------------------------------') @@ -466,8 +482,14 @@ def test_happy_path( # verify bundle is burned and has 0 balance bundleAfterBurn = riskpool.getBundle(bundleIdx).dict() assert bundleAfterBurn['state'] == 3 # enum BundleState { Active, Locked, Closed, Burned } + assert bundleAfterBurn['capital'] == 0 + assert bundleAfterBurn['lockedCapital'] == 0 assert bundleAfterBurn['balance'] == 0 + assert riskpool.getCapital() == 0 + assert riskpool.getTotalValueLocked() == 0 + assert riskpool.getBalance() == 0 + # verify bundle funds are now with investor assert bundleToken.exists(bundleNftId) == True assert bundleToken.burned(bundleNftId) == True diff --git a/tests/test_ayii_product_process_policies.py b/tests/test_ayii_product_process_policies.py index f34bfc0..2b8362e 100644 --- a/tests/test_ayii_product_process_policies.py +++ b/tests/test_ayii_product_process_policies.py @@ -367,6 +367,10 @@ def test_process_policies_mix_batch_individual_processing( requestEvent = tx[0].events['LogAyiiRiskDataRequested'][0] print('ayii requestEvent {}'.format(requestEvent)) + # attempt to process policy before oracle response is in + with brownie.reverts('ERROR:AYI-031:ORACLE_RESPONSE_MISSING'): + product.processPolicy(policyId[3], {'from': insurer}) + print('--- step test oracle response ----------------------------') @@ -410,15 +414,24 @@ def test_process_policies_mix_batch_individual_processing( print('balanceOf(riskpoolWallet): {}'.format(token.balanceOf(riskpoolWallet))) print('sumInsured[0]: {}'.format(sumInsured[0])) - - # try to trigger without insurer role + + assert product.policies(riskId[0]) == 5 + + # try to process without insurer role with brownie.reverts('AccessControl: account 0x5aeda56215b167893e80b4fe645ba6d5bab767de is missing role 0xf098b7742e998f92a3c749f35e64ef555edcecec4b78a00c532a4f385915955b'): - product.processPolicy(riskId[0], policyId[3], {'from': customer}) + product.processPolicy(policyId[3], {'from': customer}) - tx = product.processPolicy(riskId[0], policyId[3], {'from': insurer}) - print(tx.info()) + # try to process invalid processId + with brownie.reverts('ERROR:POC-101:APPLICATION_DOES_NOT_EXIST'): + product.processPolicy(s2b32('whateverId'), {'from': insurer}) + + assert product.policies(riskId[0]) == 5 - assert False + tx = product.processPolicy(policyId[3], {'from': insurer}) + print(tx.info()) + assert 'LogAyiiPolicyProcessed' in tx.events + assert tx.events['LogAyiiPolicyProcessed'][0]['policyId'] == policyId[3] + assert product.policies(riskId[0]) == 4 # claim processing for policies associated with the specified risk # batch size=2 triggers processing of 2 policies for this risk @@ -426,26 +439,15 @@ def test_process_policies_mix_batch_individual_processing( processedPolicyIds = tx.return_value assert len(processedPolicyIds) == 2 + assert product.policies(riskId[0]) == 2 assert processedPolicyIds[0] == policyId[4] - assert processedPolicyIds[1] == policyId[3] + assert processedPolicyIds[1] == policyId[2] # policyId[3] already processed individually # process another 2 policies tx = product.processPoliciesForRisk(riskId[0], 2, {'from': insurer}) processedPolicyIds = tx.return_value assert len(processedPolicyIds) == 2 - assert processedPolicyIds[0] == policyId[2] - assert processedPolicyIds[1] == policyId[1] - - # another 2 policies - BUT only one remains to be actually processed - tx = product.processPoliciesForRisk(riskId[0], 2, {'from': insurer}) - processedPolicyIds = tx.return_value - - assert len(processedPolicyIds) == 1 - assert processedPolicyIds[0] == policyId[0] - - # and finally another 2 policies - BUT none remains to be actually processed - tx = product.processPoliciesForRisk(riskId[0], 2, {'from': insurer}) - processedPolicyIds = tx.return_value - - assert len(processedPolicyIds) == 0 + assert product.policies(riskId[0]) == 0 + assert processedPolicyIds[0] == policyId[1] + assert processedPolicyIds[1] == policyId[0] From b5d2340c33647b4618c796e4bc3c242f5a3fbb92 Mon Sep 17 00:00:00 2001 From: Matthias Zimmermann Date: Fri, 16 Sep 2022 22:42:19 +0000 Subject: [PATCH 3/5] remove decreaseBalance, cleanup, fix tests --- .vscode/settings.json | 2 +- brownie-config.yaml | 4 +- contracts/examples/AyiiProduct.sol | 6 +- contracts/flows/PolicyDefaultFlow.sol | 2 +- contracts/modules/BundleController.sol | 85 ++++++++++----------- contracts/modules/PoolController.sol | 58 ++++++-------- contracts/services/RiskpoolService.sol | 41 ++-------- tests/test_ayii_product_process_policies.py | 2 +- tests/test_bundle_create_use_burn.py | 4 +- tests/test_deploy_instance.py | 2 +- 10 files changed, 80 insertions(+), 126 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index 9167aba..3750ec8 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -9,7 +9,7 @@ "solidity.remappingsUnix": [ "@openzeppelin/=/home/vscode/.brownie/packages/OpenZeppelin/openzeppelin-contracts@4.7.3", "@chainlink/=/home/vscode/.brownie/packages/smartcontractkit/chainlink@1.6.0", - "@etherisc/gif-interface/=/home/vscode/.brownie/packages/etherisc/gif-interface@fb9bc39", + "@etherisc/gif-interface/=/home/vscode/.brownie/packages/etherisc/gif-interface@736bf15", ], "solidity.compileUsingRemoteVersion": "v0.8.2+commit.661d1103", "peacock.remoteColor": "1D3C43", diff --git a/brownie-config.yaml b/brownie-config.yaml index 6bd640e..4db9d63 100644 --- a/brownie-config.yaml +++ b/brownie-config.yaml @@ -22,7 +22,7 @@ compiler: remappings: - "@openzeppelin=OpenZeppelin/openzeppelin-contracts@4.7.3" - "@chainlink=smartcontractkit/chainlink@1.6.0" - - "@etherisc/gif-interface=etherisc/gif-interface@fb9bc39" + - "@etherisc/gif-interface=etherisc/gif-interface@736bf15" # packages below will be added to brownie # you may use 'brownie pm list' after 'brownie compile' @@ -32,7 +32,7 @@ dependencies: # github dependency format: /@ - OpenZeppelin/openzeppelin-contracts@4.7.3 - smartcontractkit/chainlink@1.6.0 - - etherisc/gif-interface@fb9bc39 + - etherisc/gif-interface@736bf15 # exclude open zeppeling contracts when calculating test coverage # https://eth-brownie.readthedocs.io/en/v1.10.3/config.html#exclude_paths diff --git a/contracts/examples/AyiiProduct.sol b/contracts/examples/AyiiProduct.sol index a5dd857..1f6b0e5 100644 --- a/contracts/examples/AyiiProduct.sol +++ b/contracts/examples/AyiiProduct.sol @@ -431,9 +431,9 @@ contract AyiiProduct is bytes32 riskId = abi.decode(application.data, (bytes32)); Risk memory risk = _risks[riskId]; - require(risk.id == riskId, "ERROR:AYI-030:RISK_ID_INVALID"); - require(risk.responseAt > 0, "ERROR:AYI-031:ORACLE_RESPONSE_MISSING"); - require(EnumerableSet.contains(_policies[riskId], policyId), "ERROR:AYI-032:POLICY_FOR_RISK_UNKNOWN"); + require(risk.id == riskId, "ERROR:AYI-031:RISK_ID_INVALID"); + require(risk.responseAt > 0, "ERROR:AYI-032:ORACLE_RESPONSE_MISSING"); + require(EnumerableSet.contains(_policies[riskId], policyId), "ERROR:AYI-033:POLICY_FOR_RISK_UNKNOWN"); EnumerableSet.remove(_policies[riskId], policyId); diff --git a/contracts/flows/PolicyDefaultFlow.sol b/contracts/flows/PolicyDefaultFlow.sol index b784e29..948d226 100644 --- a/contracts/flows/PolicyDefaultFlow.sol +++ b/contracts/flows/PolicyDefaultFlow.sol @@ -147,7 +147,7 @@ contract PolicyDefaultFlow is policy.collectPremium(processId, netPremiumAmount + feeAmount); PoolController pool = getPoolContract(); - pool.increaseBalance(processId, netPremiumAmount); + pool.processPremium(processId, netPremiumAmount); } } diff --git a/contracts/modules/BundleController.sol b/contracts/modules/BundleController.sol index 4e5f83d..917a001 100644 --- a/contracts/modules/BundleController.sol +++ b/contracts/modules/BundleController.sol @@ -36,10 +36,10 @@ contract BundleController is modifier onlyFundableBundle(uint256 bundleId) { Bundle storage bundle = _bundles[bundleId]; - require(bundle.createdAt > 0, "ERROR:BUC-031:BUNDLE_DOES_NOT_EXIST"); + require(bundle.createdAt > 0, "ERROR:BUC-002:BUNDLE_DOES_NOT_EXIST"); require( bundle.state != IBundle.BundleState.Burned - && bundle.state != IBundle.BundleState.Closed, "ERROR:BUC-032:BUNDLE_BURNED_OR_CLOSED" + && bundle.state != IBundle.BundleState.Closed, "ERROR:BUC-003:BUNDLE_BURNED_OR_CLOSED" ); _; } @@ -182,6 +182,25 @@ contract BundleController is } + function processPremium(uint256 bundleId, bytes32 processId, uint256 amount) + external override + onlyRiskpoolService + onlyFundableBundle(bundleId) + { + IPolicy.Policy memory policy = _policy.getPolicy(processId); + require( + policy.state != IPolicy.PolicyState.Closed, + "ERROR:POL-030:POLICY_STATE_INVALID" + ); + + Bundle storage bundle = _bundles[bundleId]; + require(bundle.createdAt > 0, "ERROR:BUC-031:BUNDLE_DOES_NOT_EXIST"); + + bundle.balance += amount; + bundle.updatedAt = block.timestamp; // solhint-disable-line + } + + function processPayout(uint256 bundleId, bytes32 processId, uint256 amount) external override onlyRiskpoolService @@ -189,23 +208,23 @@ contract BundleController is IPolicy.Policy memory policy = _policy.getPolicy(processId); require( policy.state != IPolicy.PolicyState.Closed, - "ERROR:POL-030:POLICY_STATE_INVALID" + "ERROR:POL-040:POLICY_STATE_INVALID" ); // check there are policies and there is sufficient locked capital for policy - require(_activePolicies[bundleId] > 0, "ERROR:BUC-031:NO_ACTIVE_POLICIES_FOR_BUNDLE"); - require(_valueLockedPerPolicy[bundleId][processId] >= amount, "ERROR:BUC-032:COLLATERAL_INSUFFICIENT_FOR_POLICY"); + require(_activePolicies[bundleId] > 0, "ERROR:BUC-041:NO_ACTIVE_POLICIES_FOR_BUNDLE"); + require(_valueLockedPerPolicy[bundleId][processId] >= amount, "ERROR:BUC-042:COLLATERAL_INSUFFICIENT_FOR_POLICY"); // make sure bundle exists and is not yet closed Bundle storage bundle = _bundles[bundleId]; - require(bundle.createdAt > 0, "ERROR:BUC-033:BUNDLE_DOES_NOT_EXIST"); + require(bundle.createdAt > 0, "ERROR:BUC-043:BUNDLE_DOES_NOT_EXIST"); require( bundle.state == IBundle.BundleState.Active || bundle.state == IBundle.BundleState.Locked, - "ERROR:BUC-034:BUNDLE_STATE_INVALID"); - require(bundle.capital >= amount, "ERROR:BUC-035:CAPITAL_TOO_LOW"); - require(bundle.lockedCapital >= amount, "ERROR:BUC-036:LOCKED_CAPITAL_TOO_LOW"); - require(bundle.balance >= amount, "ERROR:BUC-037:BALANCE_TOO_LOW"); + "ERROR:BUC-044:BUNDLE_STATE_INVALID"); + require(bundle.capital >= amount, "ERROR:BUC-045:CAPITAL_TOO_LOW"); + require(bundle.lockedCapital >= amount, "ERROR:BUC-046:LOCKED_CAPITAL_TOO_LOW"); + require(bundle.balance >= amount, "ERROR:BUC-047:BALANCE_TOO_LOW"); _valueLockedPerPolicy[bundleId][processId] -= amount; bundle.capital -= amount; @@ -225,19 +244,19 @@ contract BundleController is IPolicy.Policy memory policy = _policy.getPolicy(processId); require( policy.state == IPolicy.PolicyState.Closed, - "ERROR:POL-025:POLICY_STATE_INVALID" + "ERROR:POL-050:POLICY_STATE_INVALID" ); // make sure bundle exists and is not yet closed Bundle storage bundle = _bundles[bundleId]; - require(bundle.createdAt > 0, "ERROR:BUC-024:BUNDLE_DOES_NOT_EXIST"); - require(_activePolicies[bundleId] > 0, "ERROR:BUC-025:NO_ACTIVE_POLICIES_FOR_BUNDLE"); + require(bundle.createdAt > 0, "ERROR:BUC-051:BUNDLE_DOES_NOT_EXIST"); + require(_activePolicies[bundleId] > 0, "ERROR:BUC-052:NO_ACTIVE_POLICIES_FOR_BUNDLE"); uint256 lockedForPolicyAmount = _valueLockedPerPolicy[bundleId][processId]; // this should never ever fail ... require( bundle.lockedCapital >= lockedForPolicyAmount, - "PANIC:BUC-027:UNLOCK_CAPITAL_TOO_BIG" + "PANIC:BUC-053:UNLOCK_CAPITAL_TOO_BIG" ); // policy no longer relevant for bundle @@ -252,31 +271,6 @@ contract BundleController is emit LogBundlePolicyReleased(bundleId, processId, lockedForPolicyAmount, capacityAmount); } - - function increaseBalance(uint256 bundleId, uint256 amount) - external override - onlyRiskpoolService - onlyFundableBundle(bundleId) - { - Bundle storage bundle = _bundles[bundleId]; - bundle.balance += amount; - bundle.updatedAt = block.timestamp; // solhint-disable-line - } - - - function decreaseBalance(uint256 bundleId, uint256 amount) - external override - onlyRiskpoolService - onlyFundableBundle(bundleId) - { - Bundle storage bundle = _bundles[bundleId]; - - require(bundle.balance >= amount, "ERROR:BUC-035:BUNDLE_BALANCE_TOO_SMALL"); - - bundle.balance -= amount; - bundle.updatedAt = block.timestamp; - } - function getOwner(uint256 bundleId) public view returns(address) { uint256 tokenId = getBundle(bundleId).tokenId; return _token.ownerOf(tokenId); @@ -309,7 +303,7 @@ contract BundleController is function getBundle(uint256 bundleId) public view returns(Bundle memory) { Bundle memory bundle = _bundles[bundleId]; - require(bundle.createdAt > 0, "ERROR:BUC-040:BUNDLE_DOES_NOT_EXIST"); + require(bundle.createdAt > 0, "ERROR:BUC-060:BUNDLE_DOES_NOT_EXIST"); return bundle; } @@ -347,23 +341,22 @@ contract BundleController is if (oldState == BundleState.Active) { require( newState == BundleState.Locked || newState == BundleState.Closed, - "ERROR:BUC-050:ACTIVE_INVALID_TRANSITION" + "ERROR:BUC-070:ACTIVE_INVALID_TRANSITION" ); } else if (oldState == BundleState.Locked) { require( newState == BundleState.Active || newState == BundleState.Closed, - "ERROR:BUC-051:LOCKED_INVALID_TRANSITION" + "ERROR:BUC-071:LOCKED_INVALID_TRANSITION" ); } else if (oldState == BundleState.Closed) { require( newState == BundleState.Burned, - "ERROR:BUC-052:CLOSED_INVALID_TRANSITION" + "ERROR:BUC-072:CLOSED_INVALID_TRANSITION" ); } else if (oldState == BundleState.Burned) { - revert("ERROR:BUC-053:BURNED_IS_FINAL_STATE"); + revert("ERROR:BUC-073:BURNED_IS_FINAL_STATE"); } else { - revert("ERROR:BOC-054:INITIAL_STATE_NOT_HANDLED"); + revert("ERROR:BOC-074:INITIAL_STATE_NOT_HANDLED"); } } - } diff --git a/contracts/modules/PoolController.sol b/contracts/modules/PoolController.sol index 739244d..d2f7d0d 100644 --- a/contracts/modules/PoolController.sol +++ b/contracts/modules/PoolController.sol @@ -219,33 +219,19 @@ contract PoolController is } } - function release(bytes32 processId) + + function processPremium(bytes32 processId, uint256 amount) external override onlyPolicyFlow("Pool") { - IPolicy.Policy memory policy = _policy.getPolicy(processId); - require( - policy.state == IPolicy.PolicyState.Closed, - "ERROR:POL-025:POLICY_STATE_INVALID" - ); - IPolicy.Metadata memory metadata = _policy.getMetadata(processId); IRiskpool riskpool = _getRiskpoolComponent(metadata); - riskpool.releasePolicy(processId); - - IPolicy.Application memory application = _policy.getApplication(processId); + riskpool.processPolicyPremium(processId, amount); uint256 riskpoolId = _riskpoolIdForProductId[metadata.productId]; IPool.Pool storage pool = _riskpools[riskpoolId]; - uint256 remainingCollateralAmount = _collateralAmount[processId] - policy.payoutAmount; - - pool.sumOfSumInsuredAtRisk -= application.sumInsuredAmount; - pool.lockedCapital -= remainingCollateralAmount; - pool.updatedAt = block.timestamp; // solhint-disable-line - - // free memory - delete _collateralAmount[processId]; - emit LogRiskpoolCollateralReleased(riskpoolId, processId, remainingCollateralAmount); + pool.balance += amount; + pool.updatedAt = block.timestamp; } @@ -271,33 +257,33 @@ contract PoolController is } - function increaseBalance(bytes32 processId, uint256 amount) + function release(bytes32 processId) external override onlyPolicyFlow("Pool") { + IPolicy.Policy memory policy = _policy.getPolicy(processId); + require( + policy.state == IPolicy.PolicyState.Closed, + "ERROR:POL-025:POLICY_STATE_INVALID" + ); + IPolicy.Metadata memory metadata = _policy.getMetadata(processId); IRiskpool riskpool = _getRiskpoolComponent(metadata); - riskpool.increaseBalance(processId, amount); + riskpool.releasePolicy(processId); + + IPolicy.Application memory application = _policy.getApplication(processId); uint256 riskpoolId = _riskpoolIdForProductId[metadata.productId]; IPool.Pool storage pool = _riskpools[riskpoolId]; - pool.balance += amount; - pool.updatedAt = block.timestamp; - } - + uint256 remainingCollateralAmount = _collateralAmount[processId] - policy.payoutAmount; - function decreaseBalance(bytes32 processId, uint256 amount) - external override - onlyPolicyFlow("Pool") - { - IPolicy.Metadata memory metadata = _policy.getMetadata(processId); - IRiskpool riskpool = _getRiskpoolComponent(metadata); - riskpool.decreaseBalance(processId, amount); + pool.sumOfSumInsuredAtRisk -= application.sumInsuredAmount; + pool.lockedCapital -= remainingCollateralAmount; + pool.updatedAt = block.timestamp; // solhint-disable-line - uint256 riskpoolId = _riskpoolIdForProductId[metadata.productId]; - IPool.Pool storage pool = _riskpools[riskpoolId]; - pool.balance -= amount; - pool.updatedAt = block.timestamp; + // free memory + delete _collateralAmount[processId]; + emit LogRiskpoolCollateralReleased(riskpoolId, processId, remainingCollateralAmount); } function setMaximumNumberOfActiveBundles(uint256 riskpoolId, uint256 maxNumberOfActiveBundles) diff --git a/contracts/services/RiskpoolService.sol b/contracts/services/RiskpoolService.sol index 18d2f8b..bd0aaaf 100644 --- a/contracts/services/RiskpoolService.sol +++ b/contracts/services/RiskpoolService.sol @@ -233,6 +233,13 @@ contract RiskpoolService is _bundle.collateralizePolicy(bundleId, processId, collateralAmount); } + function processPremium(uint256 bundleId, bytes32 processId, uint256 amount) + external override + onlyOwningRiskpool(bundleId, true) + { + _bundle.processPremium(bundleId, processId, amount); + } + function processPayout(uint256 bundleId, bytes32 processId, uint256 amount) external override onlyOwningRiskpool(bundleId, true) @@ -248,42 +255,10 @@ contract RiskpoolService is collateralAmount = _bundle.releasePolicy(bundleId, processId); } - - function increaseBundleBalance(uint256 bundleId, uint256 amount) - external override - onlyOwningRiskpool(bundleId, true) - returns(uint256 newBalance) - { - IBundle.Bundle memory bundle = _bundle.getBundle(bundleId); - require(bundle.state == IBundle.BundleState.Active, "ERROR:RPS-030:BUNDLE_NOT_ACTIVE"); - - _bundle.increaseBalance(bundleId, amount); - newBalance = bundle.balance + amount; - } - - function decreaseBundleBalance(uint256 bundleId, uint256 amount) - external override - onlyOwningRiskpool(bundleId, true) - returns(uint256 newBalance) - { - IBundle.Bundle memory bundle = _bundle.getBundle(bundleId); - require( - bundle.state != IBundle.BundleState.Closed - && bundle.state != IBundle.BundleState.Burned, - "ERROR:RPS-031:BUNDLE_CLOSED_OR_BURNED" - ); - - require(bundle.balance >= amount, "ERROR:RPS-032:BUNDLE_BALANCE_TOO_LOW"); - - _bundle.decreaseBalance(bundleId, amount); - newBalance = bundle.balance - amount; - } - function setMaximumNumberOfActiveBundles(uint256 riskpoolId, uint256 maxNumberOfActiveBundles) external override onlyOwningRiskpoolId(riskpoolId, true) { _pool.setMaximumNumberOfActiveBundles(riskpoolId, maxNumberOfActiveBundles); - } - + } } diff --git a/tests/test_ayii_product_process_policies.py b/tests/test_ayii_product_process_policies.py index 2b8362e..9accf1b 100644 --- a/tests/test_ayii_product_process_policies.py +++ b/tests/test_ayii_product_process_policies.py @@ -368,7 +368,7 @@ def test_process_policies_mix_batch_individual_processing( print('ayii requestEvent {}'.format(requestEvent)) # attempt to process policy before oracle response is in - with brownie.reverts('ERROR:AYI-031:ORACLE_RESPONSE_MISSING'): + with brownie.reverts('ERROR:AYI-032:ORACLE_RESPONSE_MISSING'): product.processPolicy(policyId[3], {'from': insurer}) diff --git a/tests/test_bundle_create_use_burn.py b/tests/test_bundle_create_use_burn.py index 447b5a8..33d4b8c 100644 --- a/tests/test_bundle_create_use_burn.py +++ b/tests/test_bundle_create_use_burn.py @@ -308,13 +308,13 @@ def test_close_and_burn_bundle( 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'): + with brownie.reverts('ERROR:BUC-072:CLOSED_INVALID_TRANSITION'): riskpool.closeBundle(bundleId, {'from': bundleOwner}) with brownie.reverts('ERROR:POL-044:BUNDLE_ID_NOT_IN_SET'): riskpool.lockBundle(bundleId, {'from': bundleOwner}) - with brownie.reverts('ERROR:BUC-052:CLOSED_INVALID_TRANSITION'): + with brownie.reverts('ERROR:BUC-072:CLOSED_INVALID_TRANSITION'): riskpool.unlockBundle(bundleId, {'from': bundleOwner}) with brownie.reverts('ERROR:RPS-010:BUNDLE_CLOSED_OR_BURNED'): diff --git a/tests/test_deploy_instance.py b/tests/test_deploy_instance.py index 5dcc3d5..c635ffa 100644 --- a/tests/test_deploy_instance.py +++ b/tests/test_deploy_instance.py @@ -63,7 +63,7 @@ def test_Bundle(instance: GifInstance, owner): assert bundle.bundles() == 0 - with brownie.reverts('ERROR:BUC-040:BUNDLE_DOES_NOT_EXIST'): + with brownie.reverts('ERROR:BUC-060:BUNDLE_DOES_NOT_EXIST'): bundle.getBundle(0) with pytest.raises(AttributeError): From 19640e9b07316924596667ba33a61a2d74d58ab5 Mon Sep 17 00:00:00 2001 From: Matthias Zimmermann Date: Sun, 18 Sep 2022 13:17:37 +0000 Subject: [PATCH 4/5] add collateral lifecycle test test_bundle_collateral_lifecycle.py --- contracts/test/TestProduct.sol | 26 ++ scripts/const.py | 2 +- tests/test_bundle_collateral_lifecycle.py | 496 ++++++++++++++++++++++ 3 files changed, 523 insertions(+), 1 deletion(-) create mode 100644 tests/test_bundle_collateral_lifecycle.py diff --git a/contracts/test/TestProduct.sol b/contracts/test/TestProduct.sol index da48100..a479ef0 100644 --- a/contracts/test/TestProduct.sol +++ b/contracts/test/TestProduct.sol @@ -275,6 +275,32 @@ contract TestProduct is _processPayout(policyId, payoutId); } + function newPayout( + bytes32 policyId, + uint256 claimId, + uint256 payoutAmount + ) + external + onlyOwner + returns(uint256 payoutId) + { + payoutId = _newPayout( + policyId, + claimId, + payoutAmount, + abi.encode(0)); + } + + function processPayout( + bytes32 policyId, + uint256 payoutId + ) + external + onlyOwner + { + _processPayout(policyId, payoutId); + } + function oracleCallback( uint256 requestId, bytes32 policyId, diff --git a/scripts/const.py b/scripts/const.py index 38fec52..50880a5 100644 --- a/scripts/const.py +++ b/scripts/const.py @@ -3,7 +3,7 @@ # === GIF platform ========================================================== # # GIF release -GIF_RELEASE = '1.6.0' +GIF_RELEASE = '2.0.0' # GIF modules ACCESS_NAME = 'Access' diff --git a/tests/test_bundle_collateral_lifecycle.py b/tests/test_bundle_collateral_lifecycle.py new file mode 100644 index 0000000..4095a83 --- /dev/null +++ b/tests/test_bundle_collateral_lifecycle.py @@ -0,0 +1,496 @@ +import brownie +import pytest + +from web3 import Web3 + +from brownie.network.account import Account +from brownie import ( + interface, + Wei, + TestProduct, +) + +from scripts.util import ( + s2h, + s2b32, +) + +from scripts.setup import ( + fund_riskpool, + apply_for_policy, +) + +from scripts.instance import ( + GifInstance, +) + +from scripts.product import ( + GifTestProduct, + GifTestRiskpool, +) + +# enforce function isolation for tests below +@pytest.fixture(autouse=True) +def isolation(fn_isolation): + pass + + +def test_apply_decline( + instance: GifInstance, + testCoin, + gifTestProduct: GifTestProduct, + productOwner: Account, + riskpoolKeeper: Account, + capitalOwner: Account, + owner: Account, + customer: Account +): + policyController = instance.getPolicy() + instanceService = instance.getInstanceService() + product = gifTestProduct.getContract() + riskpool = gifTestProduct.getRiskpool().getContract() + + # prepare funded riskpool + initialFunding = 10000 + fund_riskpool(instance, owner, capitalOwner, riskpool, riskpoolKeeper, testCoin, initialFunding) + + expectedBalance = 0.95 * initialFunding - 42 + expectedCapital = expectedBalance + expectedLockedCapital = 0 + + bundleId = riskpool.getBundle(0).dict()['id'] + bundle = instanceService.getBundle(bundleId).dict() + assert bundle['id'] == bundleId + assert bundle['riskpoolId'] == riskpool.getId() + assert bundle['state'] == 0 + assert bundle['capital'] == expectedCapital + assert bundle['lockedCapital'] == expectedLockedCapital + assert bundle['balance'] == expectedBalance + + # create application + (premium, sumInsured) = 50, 1000 + processId = create_application(customer, premium, sumInsured, instance, owner, product, testCoin, approve=True) + + bundle = instanceService.getBundle(bundleId).dict() + assert bundle['state'] == 0 + assert bundle['capital'] == expectedCapital + assert bundle['lockedCapital'] == expectedLockedCapital + assert bundle['balance'] == expectedBalance + + product.decline(processId) + + bundle = instanceService.getBundle(bundleId).dict() + assert bundle['state'] == 0 + assert bundle['capital'] == expectedCapital + assert bundle['lockedCapital'] == expectedLockedCapital + assert bundle['balance'] == expectedBalance + + +def test_apply_revoke( + instance: GifInstance, + testCoin, + gifTestProduct: GifTestProduct, + productOwner: Account, + riskpoolKeeper: Account, + capitalOwner: Account, + owner: Account, + customer: Account +): + policyController = instance.getPolicy() + instanceService = instance.getInstanceService() + product = gifTestProduct.getContract() + riskpool = gifTestProduct.getRiskpool().getContract() + + # prepare funded riskpool + initialFunding = 10000 + fund_riskpool(instance, owner, capitalOwner, riskpool, riskpoolKeeper, testCoin, initialFunding) + + expectedBalance = 0.95 * initialFunding - 42 + expectedCapital = expectedBalance + expectedLockedCapital = 0 + + bundleId = riskpool.getBundle(0).dict()['id'] + bundle = instanceService.getBundle(bundleId).dict() + assert bundle['state'] == 0 + assert bundle['capital'] == expectedCapital + assert bundle['lockedCapital'] == expectedLockedCapital + assert bundle['balance'] == expectedBalance + + # create application + (premium, sumInsured) = 50, 1000 + processId = create_application(customer, premium, sumInsured, instance, owner, product, testCoin, approve=False) + + bundle = instanceService.getBundle(bundleId).dict() + assert bundle['state'] == 0 + assert bundle['capital'] == expectedCapital + assert bundle['lockedCapital'] == expectedLockedCapital + assert bundle['balance'] == expectedBalance + + product.revoke(processId, {'from': customer}) + + bundle = instanceService.getBundle(bundleId).dict() + assert bundle['state'] == 0 + assert bundle['capital'] == expectedCapital + assert bundle['lockedCapital'] == expectedLockedCapital + assert bundle['balance'] == expectedBalance + + +def test_apply_underwrite( + instance: GifInstance, + testCoin, + gifTestProduct: GifTestProduct, + productOwner: Account, + riskpoolKeeper: Account, + capitalOwner: Account, + owner: Account, + customer: Account +): + policyController = instance.getPolicy() + instanceService = instance.getInstanceService() + product = gifTestProduct.getContract() + riskpool = gifTestProduct.getRiskpool().getContract() + + initialFunding = 10000 + fund_riskpool(instance, owner, capitalOwner, riskpool, riskpoolKeeper, testCoin, initialFunding) + + expectedBalance = 0.95 * initialFunding - 42 + expectedCapital = expectedBalance + expectedLockedCapital = 0 + + bundleId = riskpool.getBundle(0).dict()['id'] + bundle = instanceService.getBundle(bundleId).dict() + assert bundle['state'] == 0 + assert bundle['capital'] == expectedCapital + assert bundle['lockedCapital'] == expectedLockedCapital + assert bundle['balance'] == expectedBalance + + (premium, sumInsured) = 50, 1000 + processId = create_application(customer, premium, sumInsured, instance, owner, product, testCoin, approve=False) + + bundle = instanceService.getBundle(bundleId).dict() + assert bundle['state'] == 0 + assert bundle['capital'] == expectedCapital + assert bundle['lockedCapital'] == expectedLockedCapital + assert bundle['balance'] == expectedBalance + + product.underwrite(processId, {'from': productOwner}) + expectedLockedCapital = sumInsured + + bundle = instanceService.getBundle(bundleId).dict() + assert bundle['state'] == 0 + assert bundle['capital'] == expectedCapital + assert bundle['lockedCapital'] == expectedLockedCapital + assert bundle['balance'] == expectedBalance + + +def test_collect_premium( + instance: GifInstance, + testCoin, + gifTestProduct: GifTestProduct, + productOwner: Account, + riskpoolKeeper: Account, + capitalOwner: Account, + owner: Account, + customer: Account +): + policyController = instance.getPolicy() + instanceService = instance.getInstanceService() + product = gifTestProduct.getContract() + riskpool = gifTestProduct.getRiskpool().getContract() + + initialFunding = 10000 + (premium, sumInsured) = (50, 1000) + fund_riskpool(instance, owner, capitalOwner, riskpool, riskpoolKeeper, testCoin, initialFunding) + processId = create_application(customer, premium, sumInsured, instance, owner, product, testCoin, approve=False) + product.underwrite(processId, {'from': productOwner}) + + expectedBalance = 0.95 * initialFunding - 42 + expectedCapital = expectedBalance + expectedLockedCapital = sumInsured + + bundleId = riskpool.getBundle(0).dict()['id'] + bundle = instanceService.getBundle(bundleId).dict() + assert bundle['state'] == 0 + assert bundle['capital'] == expectedCapital + assert bundle['lockedCapital'] == expectedLockedCapital + assert bundle['balance'] == expectedBalance + + testCoin.approve(instance.getTreasury(), premium, {'from': customer}) + tx = product.collectPremium(processId, {'from': productOwner}) + print(tx.events) + + netPremium = 0.9 * premium - 3 + expectedBalance += netPremium + + bundle = instanceService.getBundle(bundleId).dict() + assert bundle['state'] == 0 + assert bundle['capital'] == expectedCapital + assert bundle['lockedCapital'] == expectedLockedCapital + assert bundle['balance'] == expectedBalance + + # add another policy + (premium2, sumInsured2) = (10, 500) + netPremium2 = 0.9 * premium2 - 3 + + processId2 = create_policy(customer, premium2, sumInsured2, instance, owner, product, testCoin) + + expectedBalance += netPremium2 + expectedLockedCapital += sumInsured2 + bundle = instanceService.getBundle(bundleId).dict() + assert bundle['state'] == 0 + assert bundle['capital'] == expectedCapital + assert bundle['lockedCapital'] == expectedLockedCapital + assert bundle['balance'] == expectedBalance + + +def test_create_claim( + instance: GifInstance, + testCoin, + gifTestProduct: GifTestProduct, + productOwner: Account, + riskpoolKeeper: Account, + capitalOwner: Account, + owner: Account, + customer: Account +): + policyController = instance.getPolicy() + instanceService = instance.getInstanceService() + product = gifTestProduct.getContract() + riskpool = gifTestProduct.getRiskpool().getContract() + + initialFunding = 10000 + (premium, sumInsured) = (50, 1000) + fund_riskpool(instance, owner, capitalOwner, riskpool, riskpoolKeeper, testCoin, initialFunding) + processId = create_policy(customer, premium, sumInsured, instance, owner, product, testCoin) + + netCapital = 0.95 * initialFunding - 42 + netPremium = 0.9 * premium - 3 + expectedCapital = netCapital + expectedLockedCapital = sumInsured + expectedBalance = netCapital + netPremium + + bundleId = riskpool.getBundle(0).dict()['id'] + bundle = instanceService.getBundle(bundleId).dict() + assert bundle['state'] == 0 + assert bundle['capital'] == expectedCapital + assert bundle['lockedCapital'] == expectedLockedCapital + assert bundle['balance'] == expectedBalance + + (claim1, claim2, claim3) = (0, 150, sumInsured - 150) + + claimAmount = 50 + claimId = create_claim_no_oracle(product, customer, productOwner, processId, claimAmount) + + bundle = instanceService.getBundle(bundleId).dict() + assert bundle['state'] == 0 + assert bundle['capital'] == expectedCapital + assert bundle['lockedCapital'] == expectedLockedCapital + assert bundle['balance'] == expectedBalance + + tx = product.newPayout(processId, claimId, claimAmount) + payoutId = tx.return_value + + bundle = instanceService.getBundle(bundleId).dict() + assert bundle['state'] == 0 + assert bundle['capital'] == expectedCapital + assert bundle['lockedCapital'] == expectedLockedCapital + assert bundle['balance'] == expectedBalance + + tx = product.processPayout(processId, payoutId) + + expectedCapital -= claimAmount + expectedLockedCapital -= claimAmount + expectedBalance -= claimAmount + + bundle = instanceService.getBundle(bundleId).dict() + assert bundle['state'] == 0 + assert bundle['capital'] == expectedCapital + assert bundle['lockedCapital'] == expectedLockedCapital + assert bundle['balance'] == expectedBalance + + claimAmount2 = 100 + (claimId2, payoutId2) = create_claim_with_payout(product, customer, productOwner, processId, claimAmount2) + + expectedCapital -= claimAmount2 + expectedLockedCapital -= claimAmount2 + expectedBalance -= claimAmount2 + + bundle = instanceService.getBundle(bundleId).dict() + assert bundle['state'] == 0 + assert bundle['capital'] == expectedCapital + assert bundle['lockedCapital'] == expectedLockedCapital + assert bundle['balance'] == expectedBalance + + +def test_expire_close_medium_claim( + instance: GifInstance, + testCoin, + gifTestProduct: GifTestProduct, + productOwner: Account, + riskpoolKeeper: Account, + capitalOwner: Account, + owner: Account, + customer: Account +): + policyController = instance.getPolicy() + instanceService = instance.getInstanceService() + product = gifTestProduct.getContract() + riskpool = gifTestProduct.getRiskpool().getContract() + + initialFunding = 10000 + (premium, sumInsured) = (50, 1000) + fund_riskpool(instance, owner, capitalOwner, riskpool, riskpoolKeeper, testCoin, initialFunding) + processId = create_policy(customer, premium, sumInsured, instance, owner, product, testCoin) + + netCapital = 0.95 * initialFunding - 42 + netPremium = 0.9 * premium - 3 + expectedCapital = netCapital + expectedLockedCapital = sumInsured + expectedBalance = netCapital + netPremium + + bundleId = riskpool.getBundle(0).dict()['id'] + bundle = instanceService.getBundle(bundleId).dict() + assert bundle['state'] == 0 + assert bundle['capital'] == expectedCapital + assert bundle['lockedCapital'] == expectedLockedCapital + assert bundle['balance'] == expectedBalance + + claimAmount = sumInsured / 2 + (claimId2, payoutId2) = create_claim_with_payout(product, customer, productOwner, processId, claimAmount) + + expectedCapital -= claimAmount + expectedLockedCapital -= claimAmount + expectedBalance -= claimAmount + + assert expectedLockedCapital == sumInsured / 2 + + product.expire(processId) + + bundle = instanceService.getBundle(bundleId).dict() + assert bundle['state'] == 0 + assert bundle['capital'] == expectedCapital + assert bundle['lockedCapital'] == expectedLockedCapital + assert bundle['balance'] == expectedBalance + + product.close(processId) + + expectedLockedCapital = 0 + bundle = instanceService.getBundle(bundleId).dict() + assert bundle['state'] == 0 + assert bundle['capital'] == expectedCapital + assert bundle['lockedCapital'] == expectedLockedCapital + assert bundle['balance'] == expectedBalance + + +def test_expire_close_max_claim( + instance: GifInstance, + testCoin, + gifTestProduct: GifTestProduct, + productOwner: Account, + riskpoolKeeper: Account, + capitalOwner: Account, + owner: Account, + customer: Account +): + policyController = instance.getPolicy() + instanceService = instance.getInstanceService() + product = gifTestProduct.getContract() + riskpool = gifTestProduct.getRiskpool().getContract() + + initialFunding = 10000 + (premium, sumInsured) = (50, 1000) + fund_riskpool(instance, owner, capitalOwner, riskpool, riskpoolKeeper, testCoin, initialFunding) + processId = create_policy(customer, premium, sumInsured, instance, owner, product, testCoin) + + netCapital = 0.95 * initialFunding - 42 + netPremium = 0.9 * premium - 3 + expectedCapital = netCapital + expectedLockedCapital = sumInsured + expectedBalance = netCapital + netPremium + + bundleId = riskpool.getBundle(0).dict()['id'] + bundle = instanceService.getBundle(bundleId).dict() + assert bundle['state'] == 0 + assert bundle['capital'] == expectedCapital + assert bundle['lockedCapital'] == expectedLockedCapital + assert bundle['balance'] == expectedBalance + + claimAmount = sumInsured + (claimId2, payoutId2) = create_claim_with_payout(product, customer, productOwner, processId, claimAmount) + + expectedCapital -= claimAmount + expectedLockedCapital -= claimAmount + expectedBalance -= claimAmount + + assert expectedLockedCapital == 0 + + product.expire(processId) + + bundle = instanceService.getBundle(bundleId).dict() + assert bundle['state'] == 0 + assert bundle['capital'] == expectedCapital + assert bundle['lockedCapital'] == expectedLockedCapital + assert bundle['balance'] == expectedBalance + + product.close(processId) + + bundle = instanceService.getBundle(bundleId).dict() + assert bundle['state'] == 0 + assert bundle['capital'] == expectedCapital + assert bundle['lockedCapital'] == expectedLockedCapital + assert bundle['balance'] == expectedBalance + + + +def create_claim_no_oracle(product, customer, productOwner, processId, claimAmount): + tx = product.submitClaimNoOracle(processId, claimAmount, {'from':customer}) + claimId = tx.return_value + product.confirmClaim(processId, claimId, claimAmount, {'from':productOwner}) + return claimId + + +def create_claim_with_payout(product, customer, productOwner, processId, claimAmount): + tx = product.submitClaimNoOracle(processId, claimAmount, {'from':customer}) + claimId = tx.return_value + + product.confirmClaim(processId, claimId, claimAmount, {'from':productOwner}) + tx = product.createPayout(processId, claimId, claimAmount, {'from':productOwner}) + payoutId = tx.return_value + + return (claimId, payoutId) + + +def create_policy(customer, premium, sumInsured, instance, owner, product, erc20token): + erc20token.transfer(customer, premium, {'from': owner}) + erc20token.approve(instance.getTreasury(), premium, {'from': customer}) + + policy_tx = product.applyForPolicy( + premium, + sumInsured, + bytes(0), + bytes(0), + {'from': customer}) + + processId = policy_tx.return_value + return processId + + +def create_application(customer, premium, sumInsured, instance, owner, product, erc20token, approve=True, printTx=False): + erc20token.transfer(customer, premium, {'from': owner}) + + if approve: + erc20token.approve(instance.getTreasury(), premium, {'from': customer}) + + # create policy + policy_tx = product.newAppliation( + premium, + sumInsured, + bytes(0), + bytes(0), + {'from': customer}) + + if printTx: + print(policy_tx.info()) + + processId = policy_tx.return_value + return processId From 8a6baddd536853b48615d35d6d8dbb16678dbf7e Mon Sep 17 00:00:00 2001 From: Matthias Zimmermann Date: Mon, 19 Sep 2022 09:22:05 +0000 Subject: [PATCH 5/5] link with latest gif-interface version --- .vscode/settings.json | 2 +- brownie-config.yaml | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index 3750ec8..735d636 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -9,7 +9,7 @@ "solidity.remappingsUnix": [ "@openzeppelin/=/home/vscode/.brownie/packages/OpenZeppelin/openzeppelin-contracts@4.7.3", "@chainlink/=/home/vscode/.brownie/packages/smartcontractkit/chainlink@1.6.0", - "@etherisc/gif-interface/=/home/vscode/.brownie/packages/etherisc/gif-interface@736bf15", + "@etherisc/gif-interface/=/home/vscode/.brownie/packages/etherisc/gif-interface@3b0002a", ], "solidity.compileUsingRemoteVersion": "v0.8.2+commit.661d1103", "peacock.remoteColor": "1D3C43", diff --git a/brownie-config.yaml b/brownie-config.yaml index 4db9d63..298a54a 100644 --- a/brownie-config.yaml +++ b/brownie-config.yaml @@ -22,7 +22,7 @@ compiler: remappings: - "@openzeppelin=OpenZeppelin/openzeppelin-contracts@4.7.3" - "@chainlink=smartcontractkit/chainlink@1.6.0" - - "@etherisc/gif-interface=etherisc/gif-interface@736bf15" + - "@etherisc/gif-interface=etherisc/gif-interface@3b0002a" # packages below will be added to brownie # you may use 'brownie pm list' after 'brownie compile' @@ -32,7 +32,7 @@ dependencies: # github dependency format: /@ - OpenZeppelin/openzeppelin-contracts@4.7.3 - smartcontractkit/chainlink@1.6.0 - - etherisc/gif-interface@736bf15 + - etherisc/gif-interface@3b0002a # exclude open zeppeling contracts when calculating test coverage # https://eth-brownie.readthedocs.io/en/v1.10.3/config.html#exclude_paths