Smart Contract: Parametric Insurance Scenario

Building Parametric Insurance with TrustWeave Smart Contracts

This guide demonstrates how to build a parametric insurance system using TrustWeave’s Smart Contract abstraction. You’ll learn how to create contracts that automatically execute based on Earth Observation (EO) data triggers, with verifiable credentials and blockchain anchoring for trust and auditability.

What You’ll Build

By the end of this tutorial, you’ll have:

  • Created a parametric insurance contract using SmartContract
  • Bound the contract with verifiable credentials
  • Anchored the contract to blockchain
  • Executed the contract based on EO data triggers
  • Generated automatic payouts when conditions are met

Architecture Overview

1
2
3
4
5
6
7
8
9
10
+-------------------------------------------------------------------+
|            Parametric Insurance Contract                          |
+-------------------------------------------------------------------+
|  EO Provider (DID)  |  Insurance (DID)  |  Blockchain Anchor    |
|  Issues VC          |  Issues VC          |  Anchors contract    |
+---------------------+-------------------+-----------------------+
| TrustWeave SmartContractService                                   |
|  Lifecycle: draft -> bind (VC + anchor) -> activate             |
|  Execute: parametric triggers, threshold checks, payout calc.     |
+-------------------------------------------------------------------+

Step 1: Setup TrustWeave

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import org.trustweave.trust.TrustWeave
import org.trustweave.trust.dsl.credential.DidMethods.KEY
import org.trustweave.trust.dsl.credential.KeyAlgorithms.ED25519
import org.trustweave.contract.models.*
import kotlinx.serialization.json.buildJsonObject
import kotlinx.serialization.json.put
import java.time.Instant
import org.trustweave.testkit.services.*

val trustWeave = TrustWeave.build {
    did { method(KEY) { algorithm(ED25519) } }
    anchor {
        chain("algorand:mainnet") {
            provider("algorand")
            options { /* configure from your Algorand client / environment */ }
        }
    }
}

val insurerDid = trustWeave.createDid { method(KEY); algorithm(ED25519) }
val insuredDid = trustWeave.createDid { method(KEY); algorithm(ED25519) }
val eoProviderDid = trustWeave.createDid { method(KEY); algorithm(ED25519) }

Step 2: Create Contract Draft

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
suspend fun createFloodInsuranceContract(
    trustWeave: TrustWeave,
    insurerDid: String,
    insuredDid: String,
    coverageAmount: Double,
    location: Location
): SmartContract {

    val contract = trustWeave.contracts.draft(
        request = ContractDraftRequest(
            contractType = ContractType.Insurance,
            executionModel = ExecutionModel.Parametric(
                triggerType = TriggerType.EarthObservation,
                evaluationEngine = "parametric-insurance"
            ),
            parties = ContractParties(
                primaryPartyDid = insurerDid,
                counterpartyDid = insuredDid
            ),
            terms = ContractTerms(
                obligations = listOf(
                    Obligation(
                        id = "payout-obligation",
                        partyDid = insurerDid,
                        description = "Pay out based on flood depth tier",
                        obligationType = ObligationType.PAYMENT
                    )
                ),
                conditions = listOf(
                    ContractCondition(
                        id = "flood-threshold-20cm",
                        description = "Flood depth >= 20cm (Tier 1)",
                        conditionType = ConditionType.THRESHOLD,
                        expression = "$.floodDepthCm >= 20"
                    ),
                    ContractCondition(
                        id = "flood-threshold-50cm",
                        description = "Flood depth >= 50cm (Tier 2)",
                        conditionType = ConditionType.THRESHOLD,
                        expression = "$.floodDepthCm >= 50"
                    ),
                    ContractCondition(
                        id = "flood-threshold-100cm",
                        description = "Flood depth >= 100cm (Tier 3)",
                        conditionType = ConditionType.THRESHOLD,
                        expression = "$.floodDepthCm >= 100"
                    )
                ),
                penalties = null,
                rewards = null,
                jurisdiction = "US",
                governingLaw = "State of North Carolina"
            ),
            effectiveDate = Instant.now().toString(),
            expirationDate = Instant.now().plusSeconds(365 * 24 * 60 * 60).toString(),
            contractData = buildJsonObject {
                put("productType", "SarFlood")
                put("coverageAmount", coverageAmount)
                put("location", buildJsonObject {
                    put("latitude", location.latitude)
                    put("longitude", location.longitude)
                    put("address", location.address)
                    put("region", location.region)
                })
                put("thresholds", buildJsonObject {
                    put("tier1Cm", 20.0)
                    put("tier2Cm", 50.0)
                    put("tier3Cm", 100.0)
                })
                put("payoutTiers", buildJsonObject {
                    put("tier1", 0.25)  // 25% of coverage
                    put("tier2", 0.50)  // 50% of coverage
                    put("tier3", 1.0)   // 100% of coverage
                })
            }
        )
    ).getOrThrow()

    println("[OK] Contract draft created: ${contract.id}")
    println("   Contract Number: ${contract.contractNumber}")
    println("   Status: ${contract.status}")

    return contract
}

data class Location(
    val latitude: Double,
    val longitude: Double,
    val address: String,
    val region: String
)

Step 3: Bind Contract

Binding issues a verifiable credential and anchors to blockchain:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
suspend fun bindInsuranceContract(
    trustWeave: TrustWeave,
    contract: SmartContract,
    insurerDid: String,
    insurerKeyId: String
): BoundContract {

    val bound = trustWeave.contracts.bindContract(
        contractId = contract.id,
        issuerDid = insurerDid,
        issuerKeyId = insurerKeyId,
        chainId = "algorand:mainnet"
    ).getOrThrow()

    println("[OK] Contract bound:")
    println("   Credential ID: ${bound.credentialId}")
    println("   Anchor TX: ${bound.anchorRef.txHash}")
    println("   Chain: ${bound.anchorRef.chainId}")
    println("   Status: ${bound.contract.status}")

    return bound
}

Step 4: Activate Contract

1
2
3
4
5
6
7
8
9
10
11
12
13
14
suspend fun activateContract(
    trustWeave: TrustWeave,
    contractId: String
): SmartContract {

    val active = trustWeave.contracts.activateContract(contractId).getOrThrow()

    println("[OK] Contract activated: ${active.id}")
    println("   Status: ${active.status}")
    println("   Effective: ${active.effectiveDate}")
    println("   Expires: ${active.expirationDate}")

    return active
}

Step 5: Process EO Data and Execute Contract

When EO data arrives (e.g., SAR flood data), process it and execute the contract:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
suspend fun processFloodDataAndExecute(
    trustWeave: TrustWeave,
    contract: SmartContract,
    floodDepthCm: Double,
    eoDataCredential: VerifiableCredential
): ExecutionResult {

    // Create execution context with trigger data
    val executionContext = ExecutionContext(
        triggerData = buildJsonObject {
            put("floodDepthCm", floodDepthCm)
            put("credentialId", eoDataCredential.id)
            put("timestamp", Instant.now().toString())
        }
    )

    // Execute contract
    val result = trustWeave.contracts.executeContract(
        contract = contract,
        executionContext = executionContext
    ).getOrThrow()

    if (result.executed) {
        println("Contract executed")
        println("   Execution Type: ${result.executionType}")
        println("   Outcomes: ${result.outcomes.size}")

        result.outcomes.forEach { outcome ->
            println("   - ${outcome.description}")
            outcome.monetaryImpact?.let {
                println("     Amount: ${it.amount} ${it.currency}")
            }
        }
    } else {
        println("Contract conditions not met")
        result.outcomes.forEach { outcome ->
            println("   - ${outcome.description}")
        }
    }

    return result
}

Step 6: Complete Workflow

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
import org.trustweave.trust.types.getOrThrowDid
import org.trustweave.trust.types.getOrThrow
import org.trustweave.did.resolver.DidResolutionResult
import org.trustweave.did.resolver.errorMessage
import org.trustweave.did.identifiers.extractKeyId
import org.trustweave.credential.results.IssuanceResult
import org.trustweave.testkit.services.*
import org.trustweave.credential.results.getOrThrow

suspend fun completeParametricInsuranceWorkflow() {
    val trustWeave = TrustWeave.build {
        did { method(KEY) { algorithm(ED25519) } }
        anchor {
            chain("algorand:mainnet") {
                provider("algorand")
                options { /* configure from your Algorand client / environment */ }
            }
        }
    }

    // Step 1: Create DIDs
    
    val insurerDid = trustWeave.createDid { method(KEY) }.getOrThrowDid()
    val insuredDid = trustWeave.createDid { method(KEY) }.getOrThrowDid()
    val eoProviderDid = trustWeave.createDid { method(KEY) }.getOrThrowDid()
    
    val insurerDoc = when (val res = trustWeave.resolveDid(insurerDid)) {
    is DidResolutionResult.Success -> res.document
    else -> throw IllegalStateException(res.errorMessage ?: "Failed to resolve DID")
}
    val insurerKeyId = insurerDoc.verificationMethod.firstOrNull()?.extractKeyId()
        ?: throw IllegalStateException("No key found")
    
    val eoProviderDoc = when (val res = trustWeave.resolveDid(eoProviderDid)) {
    is DidResolutionResult.Success -> res.document
    else -> throw IllegalStateException(res.errorMessage ?: "Failed to resolve DID")
}
    val eoProviderKeyId = eoProviderDoc.verificationMethod.firstOrNull()?.extractKeyId()
        ?: throw IllegalStateException("No key found")

    // Step 2: Create contract draft
    val contract = createFloodInsuranceContract(
        TrustWeave = trustWeave,
        insurerDid = insurerDid.value,
        insuredDid = insuredDid.value,
        coverageAmount = 1_000_000.0,
        location = Location(
            latitude = 35.2271,
            longitude = -80.8431,
            address = "Charlotte, NC",
            region = "North Carolina"
        )
    )

    // Step 3: Bind contract
    val bound = bindInsuranceContract(
        TrustWeave = trustWeave,
        contract = contract,
        insurerDid = insurerDid.value,
        insurerKeyId = insurerKeyId
    )

    // Step 4: Activate contract
    val active = activateContract(trustWeave, bound.contract.id)

    // Step 5: Simulate flood event
    // In production, this would come from EO data provider
    val floodDepth = 75.0 // cm

    // Issue EO data credential (simplified - in production, EO provider issues this)
    
    val eoDataIssuanceResult = trustWeave.issue {
        credential {
            type("EarthObservationCredential")
            issuer(eoProviderDid)
            subject {
                "floodDepthCm" to floodDepth
                "timestamp" to Instant.now().toString()
            }
            issued(Instant.now())
        }
        signedBy(eoProviderDid)
    }
    
    
    val eoDataCredential = eoDataIssuanceResult.getOrThrow()

    // Step 6: Execute contract
    val executionResult = processFloodDataAndExecute(
        TrustWeave = TrustWeave,
        contract = active,
        floodDepthCm = floodDepth,
        eoDataCredential = eoDataCredential
    )

    // Step 7: Process payout (application-specific)
    if (executionResult.executed) {
        processPayout(executionResult)
    }
}

Advanced: Custom Condition Evaluation

For production use, implement custom condition evaluators:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
class FloodConditionEvaluator : ConditionEvaluator {
    override suspend fun evaluate(
        condition: ContractCondition,
        inputData: JsonElement,
        contract: SmartContract
    ): Boolean {
        when (condition.conditionType) {
            ConditionType.THRESHOLD -> {
                val threshold = extractThreshold(condition.expression)
                val value = extractValue(inputData, "floodDepthCm")
                return value >= threshold
            }
            else -> throw UnsupportedOperationException(
                "Condition type ${condition.conditionType} not supported"
            )
        }
    }

    private fun extractThreshold(expression: String): Double {
        // Parse expression like "$.floodDepthCm >= 50"
        val match = Regex(">= (\\d+\\.?\\d*)").find(expression)
        return match?.groupValues?.get(1)?.toDouble() ?: 0.0
    }

    private fun extractValue(data: JsonElement, key: String): Double {
        return data.jsonObject[key]?.jsonPrimitive?.content?.toDouble() ?: 0.0
    }
}

Benefits of Using Smart Contracts

  1. Standardization: W3C-compliant format works across all contract types
  2. Trust: Cryptographic proof of contract terms prevents disputes
  3. Automation: Parametric execution enables instant payouts
  4. Auditability: Blockchain anchoring provides immutable audit trails
  5. Multi-Party: DIDs enable complex multi-party contracts
  6. Extensibility: Pluggable execution models for different use cases

Next Steps


This site uses Just the Docs, a documentation theme for Jekyll.