Skip to content

Commit c5f947d

Browse files
committed
feat: add rainfall_insurance contract
1 parent 3a8690e commit c5f947d

File tree

1 file changed

+117
-0
lines changed

1 file changed

+117
-0
lines changed
+117
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
// SPDX-License-Identifier: GPL-3.0
2+
pragma solidity ^0.8.12;
3+
import "../samples/HybridAccount.sol";
4+
5+
contract RainfallInsurance {
6+
struct Policy {
7+
address policyholder;
8+
uint256 premium;
9+
uint256 payoutAmount;
10+
uint256 triggerRainfall;
11+
string city;
12+
uint256 timestamp;
13+
PolicyState state;
14+
}
15+
16+
enum PolicyState {
17+
Active,
18+
Expired,
19+
Claimed
20+
}
21+
22+
struct Rainfall {
23+
uint256 rainfallInMm;
24+
uint256 updatedAt;
25+
}
26+
27+
mapping(uint256 => Policy) public policies;
28+
mapping(string => Rainfall) public currentRainfall;
29+
uint256 public constant MULTIPLIER = 3;
30+
address payable immutable helperAddr;
31+
32+
uint256 private nonce;
33+
34+
event PolicyCreated(uint256 indexed policyId, address indexed policyholder, string city, uint256 premium, uint256 payoutAmount);
35+
36+
37+
constructor(address payable _helperAddr) {
38+
helperAddr = _helperAddr;
39+
}
40+
41+
function generatePolicyId(address policyHolder, string memory city) internal returns (uint256) {
42+
nonce++;
43+
return uint256(keccak256(abi.encodePacked(policyHolder, city, block.timestamp, nonce)));
44+
}
45+
46+
function buyInsurance(
47+
uint256 triggerRainfall,
48+
string memory city
49+
) public payable returns (uint256){
50+
require(msg.value > 0, "Premium must be greater than zero");
51+
uint256 payoutAmount = msg.value * MULTIPLIER;
52+
uint256 policyId = generatePolicyId(msg.sender, city);
53+
54+
policies[policyId] = Policy(
55+
msg.sender,
56+
msg.value,
57+
payoutAmount,
58+
triggerRainfall,
59+
city,
60+
block.timestamp,
61+
PolicyState.Active
62+
);
63+
64+
emit PolicyCreated(policyId, msg.sender, city, msg.value, payoutAmount);
65+
}
66+
67+
function updateRainfall(
68+
string memory city
69+
) internal returns (Rainfall storage) {
70+
HybridAccount ha = HybridAccount(helperAddr);
71+
72+
bytes memory req = abi.encodeWithSignature(
73+
"get_rainfall(string)",
74+
city
75+
);
76+
bytes32 userKey = bytes32(abi.encode(msg.sender));
77+
(uint32 error, bytes memory ret) = ha.CallOffchain(userKey, req);
78+
79+
if (error != 0) {
80+
revert(string(ret));
81+
}
82+
83+
uint256 rainfallInMm;
84+
(rainfallInMm) = abi.decode(ret, (uint256));
85+
currentRainfall[city] = Rainfall(rainfallInMm, block.timestamp);
86+
87+
return currentRainfall[city];
88+
}
89+
90+
function checkAndPayout(uint256 policyId) public {
91+
Policy storage policy = policies[policyId];
92+
require(policy.state == PolicyState.Active, "Policy is not active");
93+
94+
if (policy.timestamp + 365 days < block.timestamp) {
95+
policy.state = PolicyState.Expired;
96+
revert("Policy expired");
97+
}
98+
99+
Rainfall storage rainfall = currentRainfall[policy.city];
100+
101+
if (
102+
rainfall.updatedAt == 0 ||
103+
rainfall.updatedAt + 24 hours < block.timestamp
104+
) {
105+
rainfall = updateRainfall(policy.city);
106+
}
107+
108+
109+
require(
110+
rainfall.rainfallInMm <= policy.triggerRainfall,
111+
"Trigger condition not met"
112+
);
113+
114+
policy.state = PolicyState.Claimed;
115+
payable(policy.policyholder).transfer(policy.payoutAmount);
116+
}
117+
}

0 commit comments

Comments
 (0)