-
Notifications
You must be signed in to change notification settings - Fork 0
05 policy lifecycle
Policies move through a two-step lifecycle:
- request stage (
PolicyDraftcreated), - bind stage (
PolicyMetadatastored and active for claims).
This split allows stake-backed readiness checks between request and activation.
PolicyManager.PolicyStatus:
-
None- no draft exists. -
Created- draft created viarequestCoverage. -
Cancelled- draft cancelled by the requesting covered vault/buyer before binding. -
Bound- policy bound and active metadata persisted.
stateDiagram-v2
[*] --> None
None --> Created: requestCoverage()
Created --> Cancelled: cancelPolicyDraft()
Created --> Bound: CoverPool.bindPolicyForRequest() -> PolicyManager.bindPolicy()
Bound --> [*]
Cancelled --> [*]
Entry: Covered vault (or its agent, recorded as buyer) calls PolicyManager.requestCoverage(...).
Recommended tuple for the CoveredVaultWrapper integration:
-
buyer:CoveredVaultWrapper, -
claimer:CoveredVaultWrapper(files claims atomically on withdrawal shortfall), -
beneficiary:CoveredVaultWrapper(receives payout and tops up user exit), -
bindPolicyHook:CoveredVaultWrapper(receivesonPolicyBoundcallback to storepolicyIdand set deposit cap).
Checks:
- pool is factory-registered,
- non-zero beneficiary/claimer/payout token,
- non-zero coverage amount and duration,
- hook address supports
IBindPolicyHook.
Effects:
- new
policyIdreserved, -
PolicyDraftstored with statusCreated, - Core committee created with id =
policyIdviaStakeManager.createCommittee(policyId, pool, duration). - Pool curator explicitly added as committee operator via
StakeManager.addOperatorToCommittee(curator, policyId).
Entry: The requesting covered vault/buyer calls cancelPolicyDraft(policyId).
Checks:
- draft exists and is
Created, - caller is draft buyer (the requesting covered vault/adapter).
Effects:
- status becomes
Cancelled, -
StakeManager.removeOperatorFromCommittee(curator, policyId)is called to release the committee resources created in Phase 1 — the curator is removed as operator and the committee slot is freed in Core, - no policy metadata is created.
Entry: Curator (pool admin) calls CoverPool.bindPolicyForRequest(...).
- draft exists and belongs to this pool,
- draft status is
Created, - quote pool and policy id match draft,
- quote beneficiary matches draft beneficiary,
- quote timing and expiration valid,
- quote signature valid under
QUOTE_SIGNER_ROLE.
-
SpecRegistry.registerSpec(specId, spec)called by pool. TheISpecimplementation must be pre-approved by the protocol admin viaSpecRegistry.approveSpec(spec)before this call will succeed; an unapproved spec causes the entire bind transaction to revert. -
StakeManager.setCommitteeVaults(policyId, vaults[], coverageLimit)binds committee backing vaults and configures TVL limits.
PolicyManager.bindPolicy(...) validates:
- caller is pool and pool is factory-registered,
- request data matches draft values,
- duration matches quote window,
- committee has at least one vault,
- committee total stake (USD) >=
coverageLimitconverted to USD via ChainlinkPriceFeed,
- committee total stake (USD) >=
- policy commit is unique.
Then it:
- marks draft as
Bound, - stores canonical
PolicyMetadata, - triggers
IBindPolicyHook.onPolicyBound(policyId, coverageLimit)(onCoveredVaultWrapper: storespolicyIdand configures the deposit cap fromcoverageLimit).
A bound policy is claimable only during:
-
startTime <= block.timestamp < maturityTime.
Claims outside this window revert in ClaimManager.
Entry: authorized claimer (typically CoveredVaultWrapper acting as claimer) calls ClaimManager.fileClaim(...), triggered atomically on withdrawal-time shortfall detection.
Checks:
-
claimApprovalRequired[policyId] == false— curator must callapproveNextClaim(policyId)between any two successive approved claims, - policy metadata exists,
-
!metadata.premiumDefaulted— filing is blocked if the policy owner has been flagged for premium default, - caller equals metadata
claimer, - requested amount > 0 and <= remaining coverage,
- evidence hash non-zero and not previously consumed for this policy,
- claim is inside coverage window (
startTime <= now < maturityTime).
Evaluation and resolution:
- resolve spec by
(pool, specId), - evaluate spec with current context,
- if non-payable → claim rejected,
- if payable → slash and settle payout to configured beneficiary; sets
claimApprovalRequired[policyId] = trueto gate the next claim.
-
policyIdremains the canonical committee id for all Core interactions. - one draft -> one bound policy metadata record.
- cumulative payouts per policy cannot exceed
coverageLimit, - each claim request is capped by current remaining coverage.
- quote signature domain is pool-specific (
quoteDomainSeparator), - policy commits are unique and cannot be re-registered.
- Verify pool registration before request.
- Verify stake readiness before bind attempts.
- Ensure vault list is valid and non-empty at bind.
- Ensure bind hook address is ERC165-compatible.
- Ensure swap routes are configured before enabling live claim payouts.
- Ensure the
ISpecimplementation is approved viaSpecRegistry.approveSpec()before attempting policy binding. An unapproved spec causesbindPolicyForRequestto revert. - After each approved claim, the curator must call
ClaimManager.approveNextClaim(policyId)to clear the approval gate before the next claim can be filed.