Skip to content

Instantly share code, notes, and snippets.

@estein9825
Created March 29, 2024 06:53
Show Gist options
  • Save estein9825/64d86edfa66debe33c15b83caf35c75b to your computer and use it in GitHub Desktop.
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=
// 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