Created
March 29, 2024 06:53
-
-
Save estein9825/64d86edfa66debe33c15b83caf35c75b to your computer and use it in GitHub Desktop.
Created using remix-ide: Realtime Ethereum Contract Compiler and Runtime. Load this file by pasting this gists URL or ID at https://remix.ethereum.org/#version=soljson-v0.8.20+commit.a1b79de6.js&optimize=false&runs=200&gist=
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// SPDX-License-Identifier: MIT | |
pragma solidity 0.8.20; | |
import "@openzeppelin/contracts/utils/Strings.sol"; | |
import "./HelperLibraries.sol"; | |
import "https://github.com/estein9825/DateUtils/src/DateUtils.sol"; | |
contract Forecast { | |
mapping(bytes32=>string) private forecast; | |
error ForecastNotFound(string message); | |
// forecast copied over from text file | |
constructor() { | |
forecast[keccak256(abi.encodePacked("2023-04-15", "denver"))] = "Hail"; | |
forecast[keccak256(abi.encodePacked("2023-04-15", "austin"))] = "Normal"; | |
forecast[keccak256(abi.encodePacked("2023-04-16", "houston"))] = "Rainfall"; | |
forecast[keccak256(abi.encodePacked("2023-04-16", "boston"))] = "Rainfall"; | |
forecast[keccak256(abi.encodePacked("2023-04-17", "phoenix"))] = "Flood"; | |
forecast[keccak256(abi.encodePacked("2023-04-18", "tampa"))] = "Hail"; | |
forecast[keccak256(abi.encodePacked("2023-04-18", "miami"))] = "Flood"; | |
forecast[keccak256(abi.encodePacked("2023-04-19", "tuscon"))] = "Normal"; | |
} | |
// Retrieve the forecast for a city on a specific date | |
function get_forecast(string memory date, string memory city) public view returns (string memory) { | |
return forecast[keccak256(abi.encodePacked(date, StringToLower._toLowercase(city)))]; | |
} | |
} | |
interface IInsurer { | |
function get_premium(uint policy_no) external view returns (uint); | |
function view_purchased_policy() external view returns (string memory); | |
function view_available_policy() external view returns (string memory); | |
function purchase_policy( | |
uint256 _flightno, | |
string memory _flightdate, | |
string memory _departurecity, | |
string memory _destinationcity) external payable returns (bool); | |
} | |
contract Insurer { | |
address payable insurer; | |
uint256 premium = 0.001 ether; | |
uint256 indemnity = 0.02 ether; | |
string[] coverages = ["hail", "flood"]; | |
uint256 no_of_policies = 0; | |
mapping(address => uint) balances; | |
address[] claimants; | |
Forecast forecast = new Forecast(); | |
struct Policy { | |
uint256 premium; | |
uint256 indemnity; | |
string[] coverages; | |
} | |
mapping(uint256 => Policy) public Policies; | |
struct PurchasedPolicy { | |
Policy policy; | |
uint256 flight_no; | |
string flightDate; | |
string departureCity; | |
string destinationCity; | |
string policyStatus; | |
address payable passanger; | |
} | |
mapping(address => PurchasedPolicy) public PurchasedPolicies; | |
event ListPurchasedPolicy( | |
address from, | |
uint256 flight_no, | |
string flightDate, | |
string departureCity, | |
string destinationCity, | |
string policyStatus | |
); | |
// initialize policies | |
constructor() payable { | |
initializePolicies(); | |
} | |
// initialize insurer as current sender | |
function initialize() payable public { | |
insurer = payable(msg.sender); | |
} | |
// build initial policy | |
function initializePolicies() private { | |
Policies[0] = Policy(premium, indemnity, coverages); | |
no_of_policies++; | |
} | |
modifier insurerInitailized() { | |
require(insurer != address(0), "Please initialize Insurer first." ); | |
_; | |
} | |
modifier onlyClaimants() { | |
require(msg.sender != insurer, "Only Claimants can access this"); | |
_; | |
} | |
modifier onlyInsurer() { | |
require(msg.sender == insurer, "Only Insurers can access this"); | |
_; | |
} | |
// retrieve available policy | |
function view_available_policy() | |
external | |
view | |
onlyClaimants insurerInitailized | |
returns (string memory) | |
{ | |
CustomErrorChecks.assembly_notZero(msg.sender); | |
string memory policyBuilder = ""; | |
for (uint i = 0; i < no_of_policies; i++) { | |
policyBuilder = string.concat(policyBuilder, "Policy No: ", | |
Strings.toString(i), ", Premium: ", | |
Strings.toString(Policies[i].premium), " wei, Indemnity: ", | |
Strings.toString(Policies[i].indemnity), " wei, Coverage 1: ", | |
Policies[i].coverages[0], ", Coverage 2: ", | |
Policies[i].coverages[1]); | |
} | |
return policyBuilder; | |
} | |
// No policies exist | |
error NoPoliciesExist(); | |
// No policies have been purchased yet | |
error NoPurchasedPolicies(); | |
// User did not purchase a policy | |
error NoPurchasedPolicy(); | |
// Not enough ether | |
error NotEnoughWei(string message); | |
// Get specific policies premium | |
function get_premium(uint policy_num) public view returns (uint) { | |
if (no_of_policies == 0) { | |
revert NoPoliciesExist(); | |
} | |
return Policies[policy_num].premium; | |
} | |
// list all purchased policies and process for loss | |
function view_all_policies() public insurerInitailized onlyInsurer { | |
CustomErrorChecks.assembly_notZero(msg.sender); | |
if (claimants.length == 0) { | |
revert NoPurchasedPolicies(); | |
} | |
for (uint256 i = 0; i < claimants.length; i++) { | |
address policy_address = claimants[i]; | |
// verify if loss occured and pay ideminity if so | |
// but only if loss wasn't already claimed | |
if (!Strings.equal(PurchasedPolicies[policy_address].policyStatus, "claimed") && | |
verify(PurchasedPolicies[policy_address].policy.coverages, | |
PurchasedPolicies[policy_address].flightDate, | |
PurchasedPolicies[policy_address].departureCity)) { | |
if (pay_indemnity(policy_address, PurchasedPolicies[policy_address].policy.indemnity)) { | |
PurchasedPolicies[policy_address].policyStatus = "claimed"; | |
} | |
} | |
emit ListPurchasedPolicy( | |
policy_address, | |
PurchasedPolicies[policy_address].flight_no, | |
PurchasedPolicies[policy_address].flightDate, | |
PurchasedPolicies[policy_address].departureCity, | |
PurchasedPolicies[policy_address].destinationCity, | |
PurchasedPolicies[policy_address].policyStatus | |
); | |
} | |
} | |
// View purchased policy | |
function view_purchased_policy() external insurerInitailized onlyClaimants view returns (string memory) { | |
CustomErrorChecks.assembly_notZero(msg.sender); | |
if (PurchasedPolicies[msg.sender].passanger == address(0)) { | |
revert NoPurchasedPolicy(); | |
} | |
Policy memory policy = PurchasedPolicies[msg.sender].policy; | |
return string.concat("Premium: ", Strings.toString(policy.premium), " wei, Idemnity: ", | |
Strings.toString(policy.indemnity), " wei, Coverage 1: ", | |
policy.coverages[0], ", Coverage 2: ", | |
policy.coverages[1], ", Flight Number: ", | |
Strings.toString(PurchasedPolicies[msg.sender].flight_no), ", Flight Date: ", | |
PurchasedPolicies[msg.sender].flightDate, ", Departure City: ", | |
PurchasedPolicies[msg.sender].departureCity, ", Destination City: ", | |
PurchasedPolicies[msg.sender].destinationCity, ", Policy Status: ", | |
PurchasedPolicies[msg.sender].policyStatus | |
); | |
} | |
// Verify if a covered instance of weather happened in the specific city on the specific date | |
function verify(string[] memory policy_coverages, string memory date, string memory city) internal view returns (bool) { | |
string memory date_forecast = forecast.get_forecast(date, city); | |
if (bytes(date_forecast).length != 0 ) { | |
date_forecast = StringToLower._toLowercase(date_forecast); | |
if (Strings.equal(date_forecast, policy_coverages[0]) || Strings.equal(date_forecast, policy_coverages[0])) { | |
return true; | |
} | |
} | |
return false; | |
} | |
// pay ideminity since the incident happened | |
// throw an error if unable to pay for some reason | |
function pay_indemnity(address claimant, uint policy_indemnity) internal returns (bool) { | |
if (view_balance() < policy_indemnity) { | |
revert NotEnoughWei(string.concat("Not enough wei to pay indemnity. Need ", | |
Strings.toString(premium), | |
" wei but have ", | |
Strings.toString(view_balance()), " wei")); | |
} | |
(bool success,) = claimant.call{value: policy_indemnity}(""); | |
require(success, "Failed to send Wei"); | |
return success; | |
} | |
// Purchase a policy | |
function purchase_policy( | |
uint256 _flightno, | |
string memory _flightdate, | |
string memory _departurecity, | |
string memory _destinationcity | |
) external payable onlyClaimants insurerInitailized returns (bool) { | |
CustomErrorChecks.assembly_notZero(msg.sender); | |
// need to make sure we only add the user once | |
if (balances[msg.sender] == 0) { | |
claimants.push(msg.sender); | |
balances[msg.sender] = msg.value; | |
} | |
PurchasedPolicies[msg.sender] = PurchasedPolicy( | |
Policy(premium, indemnity, coverages), | |
_flightno, | |
_flightdate, | |
_departurecity, | |
_destinationcity, | |
"purchased", | |
payable(msg.sender) | |
); | |
return true; | |
} | |
// Function to receive Ether. msg.data must be empty | |
receive() external payable {} | |
// Fallback function is called when msg.data is not empty | |
fallback() external payable {} | |
// get current balance | |
function view_balance() public view returns (uint256) { | |
return address(this).balance; | |
} | |
} | |
contract Passanger { | |
using DateUtils for string; | |
IInsurer insurer; | |
// set insurer to provided address | |
// can't ever be self | |
constructor(address insurerAddress) payable { | |
insurer = IInsurer(insurerAddress); | |
} | |
modifier onlyPassanger() { | |
require(msg.sender != address(insurer), "Only Passangers can access this"); | |
_; | |
} | |
// No premium found for requested policy | |
error PremiumNotDefined(string message); | |
// Not enough ether provided | |
error NotEnoughWei(string message); | |
event Log(string message); | |
event LogBytes(bytes data); | |
event LogAddress(address addr); | |
event LogUint(uint256 from); | |
// view available policies | |
function view_available_policy() public view onlyPassanger returns (string memory) { | |
CustomErrorChecks.assembly_notZero(msg.sender); | |
return insurer.view_available_policy(); | |
} | |
modifier isValidDate(string memory date) { | |
require(DateUtils.isISOformat(date), "Invalid date format. Must be yyyy-mm-dd"); | |
_; | |
} | |
// purchase the requested policy | |
// deduct the premium from passanger's account and send to insurer | |
function purchase_policy( | |
uint256 policy_no, | |
uint256 _flightno, | |
string memory _flightdate, | |
string memory _departurecity, | |
string memory _destinationcity | |
) public payable onlyPassanger isValidDate(_flightdate) returns (string memory) { | |
CustomErrorChecks.assembly_notZero(msg.sender); | |
// make sure the policy in question has a premium | |
uint256 premium = insurer.get_premium(policy_no); | |
if (premium == 0) { | |
revert PremiumNotDefined("Please specify a valid policy number"); | |
} | |
// make sure passanger has enough ether to pay for the policy | |
if (view_balance() < premium) { | |
revert NotEnoughWei(string.concat("Not enough wei to purchase policy. Need ", | |
Strings.toString(premium), | |
" wei, but have ", | |
Strings.toString(view_balance()), " wei")); | |
} | |
// purchase the policy | |
bool success = insurer.purchase_policy{value: premium}( | |
_flightno, | |
_flightdate, | |
_departurecity, | |
_destinationcity | |
); | |
require(success, "Failed to purchase policy."); | |
return "Policy purchased"; | |
} | |
// view the purchased policy | |
function view_purchased_policy() public view onlyPassanger returns (string memory) { | |
CustomErrorChecks.assembly_notZero(msg.sender); | |
string memory purchasedPolicy = insurer.view_purchased_policy(); | |
// emit DebugString(purchasedPolicy); | |
return purchasedPolicy; | |
} | |
// Function to receive Ether. msg.data must be empty | |
receive() external payable {} | |
// Fallback function is called when msg.data is not empty | |
fallback() external payable {} | |
// get current balance | |
function view_balance() public view returns (uint256) { | |
return address(this).balance; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment