Insurance
Using the Optimistic Oracle V3 to allow for verification of insurance claims.
This section covers the Insurance contract, which is available in the Optimistic Oracle V3 quick-start repo. This tutorial shows an example of how insurance claims can be resolved and settled through the Optimistic Oracle V3 (OOV3) contract.
Insurance Contract
This smart contract allows insurers to issue insurance policies by depositing the insured amount, designating the insured beneficiary, and describing the insured event.
Anyone can request payout to the insured beneficiary at any time. The Insurance contract resolves the claim through the Optimistic Oracle V3 by asserting that the insured event has occurred as of request time using the default identifier ASSERT_TRUTH
specified in UMIP-170.
If the claim is confirmed and settled through the Optimistic Oracle V3, this contract automatically pays out insurance coverage to the beneficiary. If the claim is rejected, the policy continues to be active and ready for subsequent claim attempts.
There is no limit to the number of payout requests that can be made of the same policy, however, only the first truthfully resolved request will settle the insurance payment, whereas the Optimistic Oracle V3 will settle bonds for all requests.
Development environment
This project uses forge as the Ethereum testing framework. You will also need to install Foundry, refer to Foundry installation documentation if you don’t have it already.
You will also need git
for cloning the repository, as well as bash
shell and jq
tool in order to parse transaction outputs when interacting with deployed contracts.
Clone the UMA Optimistic Oracle V3 quick-start repository and install the dependencies:
Contract implementation
The contract discussed in this tutorial can be found at dev-quickstart-oov3/src/Insurance.sol
(here) within the repo.
Contract creation and initialization
To initialize the state variables of the contract, the constructor takes two parameters:
_defaultCurrency
identifies the token used for settlement of insurance claims, as well as the bond currency for assertions and disputes. This token should be approved as whitelisted UMA collateral. Please check Approved Collateral Types for production networks or callgetWhitelist()
on the Address Whitelist contract for any of the test networks. Note that the deployed Optimistic Oracle V3 instance already has itsdefaultCurrency
added to the whitelist, so it can also be used by the Insurance contract. Alternatively, you can approve a new token address withaddToWhitelist
method in the Address Whitelist contract if working in a sandboxed UMA environment._optimisticOracleV3
is used to locate the address of UMA Optimistic Oracle V3. Address ofOptimisticOracleV3
contact can be fetched from the relevant networks file, if you are on a live network, or you can provide your own contract instance if deploying UMA Oracle contracts in your own sandboxed testing environment.
Issuing insurance
issueInsurance
method allows any insurer to deposit insuranceAmount
of defaultCurrency
tokens by designating an insurance beneficiary (payoutAddress
) and defining the insured event (insuredEvent
). Before calling this method, the insurer should have approved this contract to spend the required amount of defaultCurrency
tokens.
Internally, the issued policy is stored in the policies
mapping using the calculated policyId
key that is generated by hashing the insured event and beneficiary address.
After pulling insuranceAmount
from the caller in the issueInsurance
method, the contract emits a InsuranceIssued
event including the policyId
parameter that should be used when claiming insurance.
Submitting insurance claim
Anyone can submit an insurance claim on the issued policy by calling the requestPayout
method with the relevant policyId
parameter. This method will make an assertion with the Optimistic Oracle V3. An assertion bond is required, hence the caller should have approved this contract to spend the required minimum amount of defaultCurrency
tokens for the proposal bond (call getMinimumBond
method on the Optimistic Oracle V3).
After checking that the policyId
represents a valid insurance policy, the contract gets the current timestamp
and composes claim that the insured event has occurred as of request time, that is passed to the Optimistic Oracle V3 when making the assertion with the assertTruth
method:
Optimistic Oracle V3 pulls the required bond and returns assertionId
that is used as a key when storing the linked policyId
in the assertedPolicies
mapping. This information will be required when receiving a callback from the Optimistic Oracle V3.
Disputing insurance claim
For the sake of simplicity this contract does not implement a dispute method, but the disputer can dispute the submitted claim directly through Optimistic Oracle V3 before the liveness passes by calling its disputeAssertion
method:
The disputer should pass the assertionId
from the request above, as well as the address for receiving back bond and rewards if the disputer was right.
If the claim is disputed, the request is escalated to the UMA DVM and it can be settled only after UMA voters have resolved it. To learn more about the DVM, see the docs section on the DVM: how does UMA's Oracle work.
Settling insurance claim
Similar to disputes, claim settlement should be initiated through the Optimistic Oracle V3 contract by calling its settleAssertion
method with the same assertionId
parameter:
In case the liveness has expired or a dispute has been resolved by the UMA DVM, this call would initiate a assertionResolvedCallback
callback in the Insurance contract:
Importantly, all callbacks should be restricted to accept calls only from the Optimistic Oracle V3 to avoid someone spoofing a resolved answer:
Depending on the resolved answer received in the assertedTruthfully
callback parameter, this contract would either pay out the insured beneficiary if this was the first successful claim (in case of true
representing that insurance claim was valid) or reject the payout:
Tests and deployment
All the unit tests covering the functionality described above are available here. To execute all of them, run:
Deployment
Before deploying and interacting with the contracts export the required environment variables:
ETHERSCAN_API_KEY
: your secret API key used for contract verification on Etherscan if deploying on a public networkETH_RPC_URL
: your RPC node used to interact with the selected networkMNEMONIC
: your passphrase used to derive private keys of deployer (index 0) and any other addresses interacting with the contractsFINDER_ADDRESS
: address of the Finder contract used to locate other UMA ecosystem contracts (in order to resolve disputes you would need to use the one from a sandboxed environment). For Goerli, you can use:DEFAULT_CURRENCY_ADDRESS
: address of the token used for insurance claim settlement. This is also used as oracle bonding currency, thus, needs to be added to whitelist either by UMA governance (production networks) or testnet administrator. On Goerli you can use0xe9448D94C9b033Ff50d3B14089043bD976fC1394
that is already whitelisted and can be minted by anyone using itsallocateTo
method
Use cast
command from Foundry to locate the address of Optimistic Oracle V3:
To deploy the Insurance contract, run forge create
command.
Finally, we can verify the deployed (if deployed to a public network) contract with forge verify-contract
:
Interacting with deployed contract
The following section provides instructions on how to interact with the deployed contract from the foundry cast
tool, though one can also use it for guidance for interacting through another interface (e.g. Remix or Etherscan).
Initial setup
Export required user addresses and their derivation indices:
Make sure the user addresses above have sufficient funding for the gas to execute the transactions.
Issue insurance
Make sure to have some amount of DEFAULT_CURRENCY_ADDRESS
tokens to back potential insurance claim. If 0xe9448D94C9b033Ff50d3B14089043bD976fC1394
was used on Goerli you can mint 10,000 DBT tokens to insurance issuer account:
Approve DEFAULT_CURRENCY_ADDRESS
to be pulled by the Insurance contract:
Issue the insurance policy and grab the resulting policyId
from the emitted InsuranceIssued
event (it should be the last emitted event in the transaction and indexed policyId
is at topic index 1
):
If in doubt on the parsing of transaction receipt you can manually view full logs from tracing:
Submit insurance claim
Get the expected oracle bond:
This should be zero for 0xe9448D94C9b033Ff50d3B14089043bD976fC1394
on Goerli, but in case of other currencies make sure to have this amount of DEFAULT_CURRENCY_ADDRESS
both on the insured account (for submitting the claim) and on the insurer's account (for disputing the claim). If bond amount is non-zero, also make sure to add approval:
Now initiate the insurance claim and grab the resulting assertionId
from the emitted InsurancePayoutRequested
event (it should be the last emitted event and indexed assertionId
is at topic index 2
):
If in doubt on the parsing of transaction receipt you can manually view full logs from tracing:
Dispute insurance claim
Before liveness passes, anyone (e.g. insurer) can dispute the claim through the Optimistic Oracle V3. In case of non-zero bond amount, they must add approval for Optimistic Oracle V3 to pull the bond:
Now initiate the dispute and export related transaction hash that we will need to collect additional request parameters for resolving the dispute:
Settle insurance claim
Resolving disputes in production environment involves UMA token holders to vote on the request. Thus, testing is possible only in a sandboxed UMA ecosystem environment where the Mock Oracle is used to resolve requests:
In order to resolve request Mock Oracle expects the following parameters:
identifier
: identifier that references instructions to resolve the request (Optimistic Oracle V3 and Insurance contract uses default identifierASSERT_TRUTH
specified in UMIP-170.)time
: timestamp when the disputed assertion was madeancillaryData
: bytes encoded additional data required to resolve the request (Optimistic Oracle V3 includesassertionId
and the address of the claiming asserter)price
: numerical value to decide the outcome of the request (Optimistic Oracle V3 requires this to be1e18
in order to resolve assertion as truthful)
The commands below export the required parameters and resolves the request at the Mock Oracle:
Note that the syntax above for getting ancillary data involves stripping 0x
and transforming assertionId
and ooAsserter
to lowercase to replicate the logic how Optimistic Oracle V3 contract is composing the ancillary data. If in doubt, you can always check the emitted PriceRequestAdded
event parameters from the Mock Oracle contract in the dispute transaction traces:
Now we can settle the request through the Optimistic Oracle V3 and observe the emitted InsurancePayoutSettled
from our Insurance contract:
The above settlement transaction should also transfer INSURANCE_AMOUNT
tokens to the insured beneficiary as well as return the assertion bond plus half of disputer's bond to the claim initiator.
Alternatively, if 0
value was resolved in PRICE
(representing the asserted claim was not true), the settlement transaction should only return the bond plus half of claim initiator's bond to the disputer.
Last updated