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
- Standardization: W3C-compliant format works across all contract types
- Trust: Cryptographic proof of contract terms prevents disputes
- Automation: Parametric execution enables instant payouts
- Auditability: Blockchain anchoring provides immutable audit trails
- Multi-Party: DIDs enable complex multi-party contracts
- Extensibility: Pluggable execution models for different use cases
Next Steps
- Review Smart Contracts Core Concepts for detailed API documentation
- Explore Parametric Insurance MGA Guide for complete MGA implementation
- See Blockchain Anchoring for anchoring details
- Check API Reference for complete API documentation