Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions crop-insurance/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@

settings/Mainnet.toml
settings/Testnet.toml
history.txt
4 changes: 4 additions & 0 deletions crop-insurance/.vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@

{
"deno.enable": true,
}
18 changes: 18 additions & 0 deletions crop-insurance/.vscode/tasks.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@

{
"version": "2.0.0",
"tasks": [
{
"label": "check contracts",
"group": "test",
"type": "shell",
"command": "clarinet check"
},
{
"label": "test contracts",
"group": "test",
"type": "shell",
"command": "clarinet test"
}
]
}
11 changes: 11 additions & 0 deletions crop-insurance/Clarinet.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
[project]
name = "crop-insurance"
authors = []
description = ""
telemetry = true
requirements = []
analysis = ["check_checker"]
costs_version = 2
[contracts.automation]
path = "contracts/automation.clar"
depends_on = []
352 changes: 352 additions & 0 deletions crop-insurance/contracts/automation.clar
Original file line number Diff line number Diff line change
@@ -0,0 +1,352 @@
;; Crop Insurance Automation Smart Contract
;; Provides automated crop insurance with oracle-based claim processing

;; Constants
(define-constant contract-owner tx-sender)
(define-constant err-owner-only (err u100))
(define-constant err-not-found (err u101))
(define-constant err-already-exists (err u102))
(define-constant err-insufficient-funds (err u103))
(define-constant err-invalid-amount (err u104))
(define-constant err-policy-expired (err u105))
(define-constant err-policy-not-active (err u106))
(define-constant err-claim-exists (err u107))
(define-constant err-unauthorized (err u108))
(define-constant err-invalid-threshold (err u109))
(define-constant err-invalid-input (err u110))

;; Data Variables
(define-data-var policy-counter uint u0)
(define-data-var claim-counter uint u0)
(define-data-var oracle-address principal contract-owner)
(define-data-var min-premium uint u1000000) ;; 1 STX in microSTX
(define-data-var max-coverage uint u100000000000) ;; 100,000 STX

;; Data Maps
(define-map policies
{ policy-id: uint }
{
farmer: principal,
crop-type: (string-ascii 50),
coverage-amount: uint,
premium-paid: uint,
start-block: uint,
end-block: uint,
location: (string-ascii 100),
rainfall-threshold: uint,
temperature-threshold: uint,
is-active: bool,
claim-filed: bool
}
)

(define-map claims
{ claim-id: uint }
{
policy-id: uint,
farmer: principal,
claim-amount: uint,
rainfall-actual: uint,
temperature-actual: uint,
filed-at: uint,
status: (string-ascii 20),
approved-by: (optional principal)
}
)

(define-map farmer-policies
{ farmer: principal }
{ policy-ids: (list 50 uint) }
)

(define-map authorized-oracles
{ oracle: principal }
{ is-authorized: bool }
)

;; Read-only functions
(define-read-only (get-policy (policy-id uint))
(map-get? policies { policy-id: policy-id })
)

(define-read-only (get-claim (claim-id uint))
(map-get? claims { claim-id: claim-id })
)

(define-read-only (get-farmer-policies (farmer principal))
(default-to { policy-ids: (list) } (map-get? farmer-policies { farmer: farmer }))
)

(define-read-only (is-oracle-authorized (oracle principal))
(default-to false (get is-authorized (map-get? authorized-oracles { oracle: oracle })))
)

(define-read-only (calculate-premium (coverage-amount uint) (risk-factor uint))
(/ (* coverage-amount risk-factor) u10000)
)

(define-read-only (get-contract-balance)
(stx-get-balance (as-contract tx-sender))
)

;; Private functions
(define-private (add-policy-to-farmer (farmer principal) (policy-id uint))
(let ((current-policies (get policy-ids (get-farmer-policies farmer))))
(map-set farmer-policies
{ farmer: farmer }
{ policy-ids: (unwrap-panic (as-max-len? (append current-policies policy-id) u50)) }
)
)
)

;; Public functions - Policy Management
(define-public (create-policy
(crop-type (string-ascii 50))
(coverage-amount uint)
(duration-blocks uint)
(location (string-ascii 100))
(rainfall-threshold uint)
(temperature-threshold uint)
(risk-factor uint))
(let
(
(policy-id (+ (var-get policy-counter) u1))
(premium (calculate-premium coverage-amount risk-factor))
(start-block block-height)
;; Validate duration-blocks before using
(validated-duration (begin
(asserts! (and (> duration-blocks u0) (<= duration-blocks u52560)) err-invalid-input)
duration-blocks))
(end-block (+ block-height validated-duration))
;; Validate string inputs length
(validated-crop-type (begin
(asserts! (> (len crop-type) u0) err-invalid-input)
crop-type))
(validated-location (begin
(asserts! (> (len location) u0) err-invalid-input)
location))
)
(asserts! (>= premium (var-get min-premium)) err-invalid-amount)
(asserts! (<= coverage-amount (var-get max-coverage)) err-invalid-amount)
(asserts! (> rainfall-threshold u0) err-invalid-threshold)
(asserts! (> temperature-threshold u0) err-invalid-threshold)

(try! (stx-transfer? premium tx-sender (as-contract tx-sender)))

(map-set policies
{ policy-id: policy-id }
{
farmer: tx-sender,
crop-type: validated-crop-type,
coverage-amount: coverage-amount,
premium-paid: premium,
start-block: start-block,
end-block: end-block,
location: validated-location,
rainfall-threshold: rainfall-threshold,
temperature-threshold: temperature-threshold,
is-active: true,
claim-filed: false
}
)

(add-policy-to-farmer tx-sender policy-id)
(var-set policy-counter policy-id)
(ok policy-id)
)
)

(define-public (cancel-policy (policy-id uint))
(let ((policy (unwrap! (get-policy policy-id) err-not-found)))
(asserts! (is-eq (get farmer policy) tx-sender) err-unauthorized)
(asserts! (get is-active policy) err-policy-not-active)
(asserts! (not (get claim-filed policy)) err-claim-exists)
(asserts! (< block-height (get end-block policy)) err-policy-expired)

(map-set policies
{ policy-id: policy-id }
(merge policy { is-active: false })
)

;; Refund 50% of premium for early cancellation
(let ((refund (/ (get premium-paid policy) u2)))
(try! (as-contract (stx-transfer? refund tx-sender (get farmer policy))))
)
(ok true)
)
)

;; Public functions - Claims Management
(define-public (file-claim
(policy-id uint)
(rainfall-actual uint)
(temperature-actual uint))
(let
(
(policy (unwrap! (get-policy policy-id) err-not-found))
(claim-id (+ (var-get claim-counter) u1))
;; Validate weather data inputs before using
(validated-rainfall (begin
(asserts! (<= rainfall-actual u10000) err-invalid-input)
rainfall-actual))
(validated-temperature (begin
(asserts! (<= temperature-actual u1000) err-invalid-input)
temperature-actual))
)
(asserts! (is-eq (get farmer policy) tx-sender) err-unauthorized)
(asserts! (get is-active policy) err-policy-not-active)
(asserts! (not (get claim-filed policy)) err-claim-exists)
(asserts! (>= block-height (get start-block policy)) err-policy-not-active)
(asserts! (<= block-height (get end-block policy)) err-policy-expired)

(let ((claim-amount (calculate-claim-amount policy validated-rainfall validated-temperature)))
(map-set claims
{ claim-id: claim-id }
{
policy-id: policy-id,
farmer: tx-sender,
claim-amount: claim-amount,
rainfall-actual: validated-rainfall,
temperature-actual: validated-temperature,
filed-at: block-height,
status: "pending",
approved-by: none
}
)

(map-set policies
{ policy-id: policy-id }
(merge policy { claim-filed: true })
)

(var-set claim-counter claim-id)
(ok claim-id)
)
)
)

(define-private (calculate-claim-amount
(policy {farmer: principal, crop-type: (string-ascii 50), coverage-amount: uint, premium-paid: uint,
start-block: uint, end-block: uint, location: (string-ascii 100),
rainfall-threshold: uint, temperature-threshold: uint, is-active: bool, claim-filed: bool})
(rainfall-actual uint)
(temperature-actual uint))
(let
(
(rainfall-deficit (if (< rainfall-actual (get rainfall-threshold policy))
(- (get rainfall-threshold policy) rainfall-actual)
u0))
(temp-excess (if (> temperature-actual (get temperature-threshold policy))
(- temperature-actual (get temperature-threshold policy))
u0))
(total-impact (+ rainfall-deficit temp-excess))
(coverage (get coverage-amount policy))
(calculated-payout (if (> total-impact u0)
(/ (* coverage total-impact) (get rainfall-threshold policy))
u0))
)
;; Return the minimum of coverage or calculated payout
(if (<= calculated-payout coverage)
calculated-payout
coverage
)
)
)

(define-public (approve-claim (claim-id uint))
(let ((claim (unwrap! (get-claim claim-id) err-not-found)))
(asserts! (is-oracle-authorized tx-sender) err-unauthorized)
(asserts! (is-eq (get status claim) "pending") err-not-found)

(map-set claims
{ claim-id: claim-id }
(merge claim {
status: "approved",
approved-by: (some tx-sender)
})
)

;; Process payout
(if (> (get claim-amount claim) u0)
(try! (as-contract (stx-transfer? (get claim-amount claim) tx-sender (get farmer claim))))
true
)
(ok true)
)
)

(define-public (reject-claim (claim-id uint))
(let ((claim (unwrap! (get-claim claim-id) err-not-found)))
(asserts! (is-oracle-authorized tx-sender) err-unauthorized)
(asserts! (is-eq (get status claim) "pending") err-not-found)

(map-set claims
{ claim-id: claim-id }
(merge claim {
status: "rejected",
approved-by: (some tx-sender)
})
)
(ok true)
)
)

;; Admin functions
(define-public (add-oracle (oracle principal))
(begin
(asserts! (is-eq tx-sender contract-owner) err-owner-only)
;; Validate oracle principal is not contract owner
(asserts! (not (is-eq oracle contract-owner)) err-invalid-input)
(map-set authorized-oracles
{ oracle: oracle }
{ is-authorized: true }
)
(ok true)
)
)

(define-public (remove-oracle (oracle principal))
(begin
(asserts! (is-eq tx-sender contract-owner) err-owner-only)
;; Validate oracle exists and is authorized before removing
(asserts! (is-some (map-get? authorized-oracles { oracle: oracle })) err-not-found)
(asserts! (is-oracle-authorized oracle) err-not-found)
(map-delete authorized-oracles { oracle: oracle })
(ok true)
)
)

(define-public (update-min-premium (new-min uint))
(begin
(asserts! (is-eq tx-sender contract-owner) err-owner-only)
;; Validate new minimum premium is reasonable
(asserts! (and (> new-min u0) (<= new-min u1000000000)) err-invalid-input)
(var-set min-premium new-min)
(ok true)
)
)

(define-public (update-max-coverage (new-max uint))
(begin
(asserts! (is-eq tx-sender contract-owner) err-owner-only)
;; Validate new maximum coverage is reasonable
(asserts! (and (> new-max u0) (>= new-max (var-get min-premium))) err-invalid-input)
(var-set max-coverage new-max)
(ok true)
)
)

(define-public (fund-contract (amount uint))
(begin
(asserts! (is-eq tx-sender contract-owner) err-owner-only)
(stx-transfer? amount tx-sender (as-contract tx-sender))
)
)

(define-public (withdraw-funds (amount uint) (recipient principal))
(begin
(asserts! (is-eq tx-sender contract-owner) err-owner-only)
(asserts! (<= amount (get-contract-balance)) err-insufficient-funds)
(as-contract (stx-transfer? amount tx-sender recipient))
)
)
Loading