Skip to content

Commit

Permalink
Merge pull request #556 from etherisc/feature/fire-deploy-script
Browse files Browse the repository at this point in the history
add deploy script for fire components (#502)
  • Loading branch information
doerfli authored Jul 26, 2024
2 parents 09c5b9a + 94882ba commit 93a7619
Show file tree
Hide file tree
Showing 8 changed files with 306 additions and 28 deletions.
36 changes: 17 additions & 19 deletions contracts/examples/fire/FireProduct.sol
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.20;

import {ACTIVE, COLLATERALIZED, PAUSED} from "../../type/StateId.sol";
import {ACTIVE, PAUSED} from "../../type/StateId.sol";
import {Amount, AmountLib} from "../../type/Amount.sol";
import {BasicProduct} from "../../product/BasicProduct.sol";
import {ClaimId} from "../../type/ClaimId.sol";
Expand All @@ -14,12 +14,9 @@ import {POLICY} from "../../type/ObjectType.sol";
import {ReferralLib} from "../../type/Referral.sol";
import {RiskId, RiskIdLib} from "../../type/RiskId.sol";
import {Seconds} from "../../type/Seconds.sol";
import {StateId} from "../../type/StateId.sol";
import {Timestamp, TimestampLib} from "../../type/Timestamp.sol";
import {UFixed, UFixedLib} from "../../type/UFixed.sol";

uint64 constant SPECIAL_ROLE_INT = 11111;

// solhint-disable-next-line func-name-mixedcase
function HALF_YEAR() pure returns (Seconds) {
return Seconds.wrap(180 * 86400);
Expand Down Expand Up @@ -161,13 +158,13 @@ contract FireProduct is
view
returns (Amount premiumAmount)
{
RiskId riskId = _riskMapping[cityName];
if (riskId.eqz()) {
RiskId risk = _riskMapping[cityName];
if (risk.eqz()) {
revert ErrorFireProductCityUnknown(cityName);
}
premiumAmount = calculatePremium(
sumInsured,
riskId,
risk,
lifetime,
"",
bundleNftId,
Expand Down Expand Up @@ -203,19 +200,19 @@ contract FireProduct is
returns (NftId policyNftId)
{
address applicationOwner = msg.sender;
RiskId riskId = initializeCity(cityName);
RiskId risk = initializeCity(cityName);

Amount premiumAmount = calculatePremium(
sumInsured,
riskId,
risk,
lifetime,
"",
bundleNftId,
ReferralLib.zero());

return _createApplication(
applicationOwner,
riskId,
risk,
sumInsured,
premiumAmount,
lifetime,
Expand All @@ -229,15 +226,15 @@ contract FireProduct is
string memory cityName
)
public
returns (RiskId riskId)
returns (RiskId risk)
{
if (! _riskMapping[cityName].eqz()) {
return _riskMapping[cityName];
}
_cities.push(cityName);
riskId = RiskIdLib.toRiskId(cityName);
_createRisk(riskId, "");
_riskMapping[cityName] = riskId;
risk = RiskIdLib.toRiskId(cityName);
_createRisk(risk, "");
_riskMapping[cityName] = risk;
}

/// @dev Calling this method will lock the sum insured amount in the pool and activate the policy at the given time.
Expand Down Expand Up @@ -332,10 +329,10 @@ contract FireProduct is
IPolicy.PolicyInfo memory policyInfo = _getInstanceReader().getPolicyInfo(policyNftId);
_checkClaimConditions(policyNftId, policyInfo, fireId);

Fire memory fire = _fires[fireId];
Fire memory theFire = _fires[fireId];
_claimed[fireId][policyNftId] = true;

Amount claimAmount = _getClaimAmount(policyNftId, policyInfo.sumInsuredAmount, fire.damageLevel);
Amount claimAmount = _getClaimAmount(policyNftId, policyInfo.sumInsuredAmount, theFire.damageLevel);

claimId = _submitClaim(policyNftId, claimAmount, abi.encodePacked(fireId));
_confirmClaim(policyNftId, claimId, claimAmount, "");
Expand All @@ -350,6 +347,7 @@ contract FireProduct is
uint256 fireId
)
internal
view
{
// check fire exists
if (_fires[fireId].reportedAt.eqz()) {
Expand All @@ -366,14 +364,14 @@ contract FireProduct is
revert ErrorFireProductAlreadyClaimed();
}

Fire memory fire = _fires[fireId];
Fire memory theFire = _fires[fireId];

// check fire is during policy lifetime
if (fire.reportedAt < policyInfo.activatedAt) {
if (theFire.reportedAt < policyInfo.activatedAt) {
revert ErrorFireProductPolicyNotYetActive(policyNftId, policyInfo.activatedAt);
}

if (fire.reportedAt >= policyInfo.expiredAt) {
if (theFire.reportedAt >= policyInfo.expiredAt) {
revert ErrorFireProductPolicyExpired(policyNftId, policyInfo.expiredAt);
}
}
Expand Down
1 change: 1 addition & 0 deletions docs/modules/ROOT/nav.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,5 @@
* xref:arch.adoc[Architecture]
* xref:howto-documentation.adoc[Documentation Howto]
* xref:setup.adoc[Development setup]
* xref:example-fire.adoc[Fire insurance example]
* https://github.com/etherisc/gif-next/issues/new[Report a bug]
94 changes: 94 additions & 0 deletions docs/modules/ROOT/pages/example-fire.adoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
= Fire insurance example

:toc:

== Overview

The fire components is a minimal fully functional and permissioned example for a insurance product built on the GIF. It consists of the following components:

- FirePoolAuthorization: A contract that authorizes the functions on the pool
- FirePool: A pool that holds the funds for the insurance product
- FireProductAuthorization: A contract that authorizes the functions on the product
- FireProduct: The insurance product that is used to insure against fires
- (optional) FireUSD: A ERC20 token that is used as the currency for the insurance product

The product is build in such a way that a customer can buy a policy which insures against fires in a specific city. The product owner can report fires in the city (the report also contains the damage level and the time of the fire). Once a fire has been reported in a city, the customer can submit a claim for the policy and receive an immediate payout (if the policy is eligable for a payout). The payout amount is calculated from the damage level and the sum insured.

The payout is 25% for small fires, 50% for medium fires and 100% for large fires. If the payout exceeds the sum insured, only the remaining sum insured is paid out. If the payout amount is the same as the sum insured after the payout, the policy is automatically expired.


== Deployment

=== With Remix

1. Checkout repository `gif-next`` (https://github.com/etherisc/gif-next.git) in Remix IDE
2. Call 'Update submodules' (Link at the bottom left of the page)
3. Open the `InstanceService` contract in directory `contracts/instance/InstanceService.sol` and compile it
4. Switch to the `Deploy & Run Transactions` tab and connect to the network of choice (must have a GIF deployment)
5. Connect to the existing `InstanceService` contract
6. Call the `createInstance` function (no arguments) and find the log `LogInstanceCloned` that shows the address of the new instance in field `instance` and the instance nft id in field `instanceNftId`
7. Now compile the contracts `FireUSD.sol`, `FirePoolAuthorization`, `FirePool`, `FireProductAuthorization` and `FireProduct` in the directory `contracts/examples/fire`
8. Deploy the FireUSD contract and save the address. You can also use any pre-existing ERC20 Token.
9. Deploy the FirePoolAuthorization contract with an arbitrary unique name and save the address.
10. Deploy tye FireProductAuthorization contract with an arbitrary unique name and save the address.
11. Deploy the FirePool contract and save the address. The pool requires the registry address, the instance nft id, the name of the component (same as used in step 9) , the address of the token as well as the address of the pool authorization contract as arguments.
12. Call `register` on the `FirePool` contract.
13. Get the nft if of the pool by calling `getNftId` function on the `FirePool` contract
14. Deploy the FireProduct contract and save the address. The product requires the registry address, the instance nft id, the name of the component (same as used in step 10) , the address of the token as well as the address of the pool and the address of the product authorization contract as arguments.
15. Call `register` on the `FireProduct` contract
16. Get the nft if of the product by calling `getNftId` function on the `FireProduct` contract
17. Congratulations, the fire product is now deployed and ready to use


=== Using the hardhat script

Run the script `scripts/deploy_fire_components.ts` on an instance that has a gif deployment. The script will deploy the FireUSD, FirePoolAuthorization, FirePool, FireProductAuthorization and FireProduct contracts and register the pool and product in the instance.

It requires the following environment variables to be set:

```
AMOUNTLIB_ADDRESS
FEELIB_ADDRESS
NFTIDLIB_ADDRESS
REFERRALLIB_ADDRESS
OBJECTTYPELIB_ADDRESS
RISKIDLIB_ADDRESS
ROLEIDLIB_ADDRESS
SECONDSLIB_ADDRESS
SELECTORLIB_ADDRESS
STRLIB_ADDRESS
TIMESTAMPLIB_ADDRESS
UFIXEDLIB_ADDRESS
VERSIONPARTLIB_ADDRESS
INSTANCE_SERVICE_ADDRESS
```

== Usage

=== Bundle creation

1. The investor must call `createBundle` on the `FirePool` contract with the `fee`, the `initialAmount` of the bundle and the `lifetime` of the bundle as arguments.
2. The response contains the `bundleNftId` which is required when purchasing policies.

=== Registration of cities

1. Registration of new cities is done via call to the method `initializeCity` on the `FireProduct` contract. Anybody can call this function.

=== Reporting of fires

1. To report a fire make sure the city is registered first.
2. Then the `ProductOwner` must call `reportFire` with a unique `fireId` as well as the `cityName`,the damage level (Small - 25% payout, Medium - 50% payout, Large - 100% payout) and the time the fire occured.

=== Policy purchase

1. Make sure the city is registered beforehand
2. As customer, call `calculatePremium` on `FireProduct` with arguments `cityName`, `sumInsured`, `lifetime` and `bundleNftId` to get the premium amount for this parameter combination.
3. As customer, call `createApplication` with the `cityName`, `sumInsured`, `lifetime` and `bundleNftId` to create a new application. The response contains the `policyNftId` that is needed for the next step.
4. Once the application is created, the `ProductOwner` must confirm the application by calling `createPolicy` with the `policyNftId` and time the policy is active (`activateAt`) as arguments.

=== Claim & Payout

1. After a fire was reported, the customer can now submit a claim and received a payout for this fire by calling `submitClaim` with the `policyNftId` and the `fireId` as arguments. The payout is calculated based on the damage level reported and the sum insured.
2. The payout amount is immediately transferred to the customer.
3. If the payout amount exceeds the sum insured, only the remaining sum insured is paid out.
4. If the payout amount is the same as the sum insured after the payout, the policy is automatically expired.
12 changes: 12 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@
"abi-coder": "^5.0.0",
"antlr4ng": "^3.0.4",
"ethers": "^6.7.1",
"ethers-decode-error": "^2.1.3",
"solidity-docgen": "^0.6.0-beta.36",
"winston": "^3.10.0"
}
Expand Down
16 changes: 8 additions & 8 deletions scripts/deploy_all.ts
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ function printAddresses(
addresses += `${libName}=${libraries[lib]}\n`;
}

addresses += `--------\n`;
addresses += `# --------\n`;
addresses += `REGISTRY_ADMIN_ADDRESS=${registry.registryAdminAddress}\n`;
addresses += `RELEASE_REGISTRY_ADDRESS=${registry.releaseRegistryAddress}\n`;
addresses += `REGISTRY_ADDRESS=${registry.registryAddress}\n`;
Expand All @@ -143,7 +143,7 @@ function printAddresses(
addresses += `STAKING_NFT_ID=${registry.stakingNftId}\n`;
addresses += `STAKING_ADDRESS=${registry.stakingAddress}\n`;
addresses += `DIP_ADDRESS=${registry.dipAddress}\n`;
addresses += `--------\n`;
addresses += `# --------\n`;
addresses += `REGISTRY_SERVICE_MANAGER_ADDRESS=${services.registryServiceManagerAddress}\n`;
addresses += `REGISTRY_SERVICE_ADDRESS=${services.registryServiceAddress}\n`;
addresses += `REGISTRY_SERVICE_NFT_ID=${services.registryServiceNftId}\n`;
Expand All @@ -168,9 +168,9 @@ function printAddresses(
addresses += `POOL_SERVICE_ADDRESS=${services.poolServiceAddress}\n`;
addresses += `POOL_SERVICE_NFT_ID=${services.poolServiceNftId}\n`;

addresses += `PRODUCT_SERVICE_MANAGER_ADDRESS=${services.productServiceManagerAddress}\n`;
addresses += `PRODUCT_SERVICE_ADDRESS=${services.productServiceAddress}\n`;
addresses += `PRODUCT_SERVICE_NFT_ID=${services.productServiceNftId}\n`;
addresses += `PRODUCT_SERVICE_MANAGER_ADDRESS=${services.riskServiceManagerAddress}\n`;
addresses += `PRODUCT_SERVICE_ADDRESS=${services.riskServiceAddress}\n`;
addresses += `PRODUCT_SERVICE_NFT_ID=${services.riskServiceNftId}\n`;

addresses += `APPLICATION_SERVICE_MANAGER_ADDRESS=${services.applicationServiceManagerAddress}\n`;
addresses += `APPLICATION_SERVICE_ADDRESS=${services.applicationServiceAddress}\n`;
Expand All @@ -187,22 +187,22 @@ function printAddresses(
addresses += `BUNDLE_SERVICE_MANAGER_ADDRESS=${services.bundleServiceManagerAddress}\n`;
addresses += `BUNDLE_SERVICE_ADDRESS=${services.bundleServiceAddress}\n`;
addresses += `BUNDLE_SERVICE_NFT_ID=${services.bundleServiceNftId}\n`;
addresses += `--------\n`;
addresses += `# --------\n`;
addresses += `MASTER_INSTANCE_ADDRESS=${masterInstance.instanceAddress}\n`;
addresses += `MASTER_INSTANCE_NFT_ID=${masterInstance.instanceNftId}\n`;
addresses += `MASTER_INSTANCE_AUTHORIZATION_V3_ADDRESS=${masterInstance.instanceAuthorizationV3Address}\n`;
addresses += `MASTER_INSTANCE_ADMIN_ADDRESS=${masterInstance.instanceAdminAddress}\n`;
addresses += `MASTER_BUNDLE_SET_ADDRESS=${masterInstance.instanceBundleSetAddress}\n`;
addresses += `MASTER_INSTANCE_READER_ADDRESS=${masterInstance.instanceReaderAddress}\n`;
addresses += `MASTER_INSTANCE_STORE_ADDRESS=${masterInstance.instanceStoreAddress}\n`;
addresses += `--------\n`;
addresses += `# --------\n`;
addresses += `CLONED_INSTANCE_ADDRESS=${clonedInstance.instanceAddress}\n`;
addresses += `CLONED_INSTANCE_NFT_ID=${clonedInstance.instanceNftId}\n`;
addresses += `CLONED_INSTANCE_ADMIN_ADDRESS=${clonedInstance.instanceAdminAddress}\n`;
addresses += `CLONED_BUNDLE_SET_ADDRESS=${clonedInstance.instanceBundleSetAddress}\n`;
addresses += `CLONED_INSTANCE_READER_ADDRESS=${clonedInstance.instanceReaderAddress}\n`;
addresses += `CLONED_INSTANCE_STORE_ADDRESS=${clonedInstance.instanceStoreAddress}\n`;
addresses += `--------\n`;
addresses += `# --------\n`;
// addresses += `tokenAddress: ${tokenAddress}\n`;
// addresses += `poolAddress: ${poolAddress}\n`;
// addresses += `poolNftId: ${poolNftId}\n`;
Expand Down
Loading

0 comments on commit 93a7619

Please sign in to comment.