// SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.2; import "@etherisc/gif-interface/contracts/components/Product.sol"; contract TerraGuardProduct is Product { // constants bytes32 public constant VERSION = "0.0.1"; bytes32 public constant POLICY_FLOW = "PolicyDefaultFlow"; uint256 public constant TYPE_5_PLUS = 5; uint256 public constant TYPE_7_PLUS = 7; // leads to %5 premiums on object value uint256 public constant OBJECT_VALUE_DIVISOR = 20; // payout specs uint256 public constant PAYOUT_FACTOR_MEDIUM = 20; uint256 public constant PAYOUT_FACTOR_LARGE = 100; string public constant CALLBACK_METHOD_NAME = "oracleCallback"; // variables // TODO should be framework feature bytes32[] private _applications; uint256 public _oracleId; // events event LogTerraGuardApplicationCreated( bytes32 processId, address policyHolder, uint256 premium, uint256 sumInsured, uint16 locationId, uint8 protectionType ); event LogTerraGuardPolicyCreated(bytes32 processId); event LogTerraGuardPolicyExpired(bytes32 processId); event LogTerraGuardClaimConfirmed( bytes32 processId, uint256 claimId, uint256 payoutAmount ); event LogTerraGuardPayoutExecuted( bytes32 processId, uint256 claimId, uint256 payoutId, uint256 payoutAmount ); constructor( bytes32 productName, address token, uint256 riskpoolId, address registry ) Product(productName, token, POLICY_FLOW, riskpoolId, registry) { } function applyForPolicy( uint8 protectionType, uint16 locationId, uint256 sumInsuredAmount, uint256 premiumAmount ) external returns (bytes32 processId) { // Create and underwrite new application address policyHolder = msg.sender; bytes memory metaData = ""; bytes memory applicationData = encodeApplicationParametersToData( protectionType, locationId ); processId = _newApplication( policyHolder, premiumAmount, sumInsuredAmount, metaData, applicationData ); _applications.push(processId); emit LogTerraGuardApplicationCreated( processId, policyHolder, premiumAmount, sumInsuredAmount, locationId, protectionType ); } function underwrite(bytes32 processId) external onlyOwner { _underwrite(processId); emit LogTerraGuardPolicyCreated(processId); } function applications() external view returns (uint256 numberOfApplications) { return _applications.length; } function getApplicationId( uint256 idx ) external view returns (bytes32 processId) { require( idx < _applications.length, "ERROR:TGP-001:APPLICATION_INDEX_TOO_LARGE" ); return _applications[idx]; } function decodeApplicationParameterFromData( bytes memory data ) public pure returns ( uint8 protectionType, uint16 locationId ) { return abi.decode(data, (uint8, uint16)); } function encodeApplicationParametersToData( uint8 protectionType, uint16 locationId ) public pure returns (bytes memory data) { return abi.encode(protectionType, locationId); } function calculatePremium( uint256 objectValue ) public pure returns (uint256 premiumAmount) { return objectValue / OBJECT_VALUE_DIVISOR; } function expirePolicy(bytes32 processId) external onlyOwner { // Get policy data IPolicy.Application memory application = _getApplication(processId); _expire(processId); emit LogTerraGuardPolicyExpired(processId); } function _handleClaim( bytes32 policyId, address payable policyHolder, uint256 sumInsured, bytes1 fireCategory ) internal { uint256 payoutAmount = _calculatePayoutAmount(sumInsured, fireCategory); // no claims handling for payouts == 0 if (payoutAmount > 0) { uint256 claimId = _newClaim(policyId, payoutAmount, ""); _confirmClaim(policyId, claimId, payoutAmount); emit LogTerraGuardClaimConfirmed(policyId, claimId, payoutAmount); uint256 payoutId = _newPayout(policyId, claimId, payoutAmount, ""); emit LogTerraGuardClaimConfirmed(policyId, claimId, payoutAmount); _processPayout(policyId, payoutId); emit LogTerraGuardPayoutExecuted( policyId, claimId, payoutId, payoutAmount ); } } function _calculatePayoutAmount( uint256 sumInsured, bytes1 fireCategory ) internal pure returns (uint256 payoutAmount) { if (fireCategory == "M") { payoutAmount = (PAYOUT_FACTOR_MEDIUM * sumInsured) / 100; } else if (fireCategory == "L") { payoutAmount = (PAYOUT_FACTOR_LARGE * sumInsured) / 100; } else { // small fires considered below deductible, no payout payoutAmount = 0; } } }