-
Notifications
You must be signed in to change notification settings - Fork 0
02 smart contracts
Coverage contracts are the policy and payout application layer over Catalysis Core. They are responsible for policy issuance semantics, premium collection/routing, and claim execution, while Core handles committee stake and SSP-level execution.
graph LR
CPF[CoverPoolFactory]
CP[CoverPool]
PM[PolicyManager]
CM[ClaimManager]
PRM[PremiumManager]
SR[SpecRegistry]
SW[Swapper]
UV3[UniswapV3Adapter]
CVW[CoveredVaultWrapper]
CPF --> CP
PM --> CP
CP --> PM
CP --> SR
PM --> CM
CVW --> PRM
CVW --> CM
CM --> SR
CM --> SW
SW --> UV3
Role: Deploys and tracks CoverPool clones.
Pattern and state:
- UUPS upgradeable proxy.
- Deploys deterministic minimal proxy clones using
Clones.cloneDeterministic. - Maintains an internal pool set and pagination helpers.
Key functions:
-
createCoverPool(params)creates and initializes a pool clone, grants curator ownership. -
computeCoverPoolAddress(params)predicts deterministic clone address. -
coverPoolExists(pool)validates whether a pool is factory-created.
Note: On EigenLayer, duration vaults act as operators and are auto-deployed during committee creation.
Key role:
-
CREATOR_ROLEcontrols pool creation and major factory settings.
Role: Curator-owned underwriting pool for quote validation and policy binding.
Pattern and state:
- Intended for minimal-clone deployment.
- Uses
AccessControlDefaultAdminRulesUpgradeablefor admin transfer safety. - Maintains bound policy commits and per-policy bound metadata.
Key functions:
-
bindPolicyForRequest(policyId, quote, spec, vaults, signature)performs:- draft checks via
PolicyManager, - EIP-712 quote signature verification,
- spec registration in
SpecRegistry, - committee vault binding in Core via
StakeManager, - final policy bind callback into
PolicyManager.
- draft checks via
-
setPoolFeeBps(...),setFeeRecipient(...)configure pool economics.
Key role:
-
QUOTE_SIGNER_ROLEdefines trusted quote signers.
Role: Policy draft and bound-policy authority.
Pattern and state:
- UUPS upgradeable proxy.
- Stores draft records (
PolicyDraft) and canonical bound metadata (PolicyMetadata). - Tracks next policy id and policy commit uniqueness.
Key functions:
-
requestCoverage(...):- called by the
CoveredVaultWrapper(or more generally a covered vault / its agent) as thebuyer, - commonly sets
claimertoCoveredVaultWrapper(files claims atomically on withdrawal shortfall), - commonly sets
beneficiarytoCoveredVaultWrapperfor atomic shortfall top-ups, - validates pool and hook,
- creates policy draft,
- creates Core committee with
committeeId = policyIdviaStakeManager.createCommittee(policyId, pool, duration), - then explicitly calls
StakeManager.addOperatorToCommittee(curator, policyId)to register the pool curator as operator.
- called by the
-
bindPolicy(request, boundPolicy):- callable by pool only,
- validates request/draft/quote consistency,
- verifies stake and vault readiness through Core,
- stores canonical policy metadata,
- calls
IBindPolicyHook.onPolicyBound(policyId, coverageLimit).
Role: Premium split and restaker reward routing bridge into Core.
Pattern and state:
- UUPS upgradeable proxy.
- Holds platform configuration:
platformTreasury,platformFeeBps. - Maintains an admin-controlled set of approved premium tokens;
distributePremiumreverts for any unapproved token.
Key functions:
-
distributePremium(pool, policyId, premiumToken, amount):- permissionless entrypoint — any caller (typically
CoveredVaultWrapper.collectPremium()) may call it, - requires:
poolhas a bound policy forpolicyId,premiumTokenis in the approved token set, - pulls
amountfrom the caller viasafeTransferFrom, so the caller must have approvedPremiumManagerfirst, - computes split: platform / pool / restaker,
- transfers platform fee to
platformTreasury, - transfers pool fee to pool
feeRecipient, - calls
RewardsManager.distributeRewards(policyId, curator, restakerSplit, token, taskId);RewardsManagerthen pulls the restaker share fromPremiumManagerto itself and routes viaSSPRouter.
- permissionless entrypoint — any caller (typically
-
approveSpender(token, spender, amount)grants a spender (typicallyRewardsManager) an unlimited allowance to pull the restaker share fromPremiumManager. -
addApprovedPremiumToken(token)/removeApprovedPremiumToken(token)admin management of allowed premium tokens. -
isApprovedPremiumToken(token)/approvedPremiumTokens()view helpers. -
getFeeSplits(...)deterministic split helper.
Access control: DEFAULT_ADMIN_ROLE for configuration; distributePremium has no role requirement.
Role: Claim execution engine from filing to payout.
Pattern and state:
- UUPS upgradeable proxy.
- Maintains per-policy claim counters, claim records, and cumulative paid-out amount.
Key functions:
-
fileClaim(policyId, requestedAmount, evidenceHash, additionalData):- file-and-resolve entrypoint (single transaction),
- requires
claimApprovalRequired[policyId] == false; curator must callapproveNextClaimbetween successive claims, - validates coverage window, remaining coverage, non-zero/unique evidence hash, and
!premiumDefaulted, - requires caller equals policy
claimer, - resolves spec and runs evaluation,
- if payable, executes slashing and collateral processing, then sets
claimApprovalRequired[policyId] = true, - transfers payout to beneficiary.
-
approveNextClaim(policyId)— called by the policy curator to clear the approval gate after each approved claim. -
claimApprovalRequired(policyId)— view: whether curator approval is required before the next claim. -
remainingCoverage(policyId)and read models for claims.
Slashing and payout mechanics (token-native, no oracle):
-
SlashingManager.previewSlashing(committeeId, operator)returns per-vault collateral tokens and token-native stake amounts. -
_computeVaultSlashesquotes each cross-token stake viaSwapper.quoteSwapto determine payout-equivalent values, then computes proportional token-native slash amounts per vault; cross-token amounts are inflated by1 / (1 - maxSwapSlippageBps)to absorb worst-case swap slippage. -
SlashingManager.executeSlashing(committeeId, operator, VaultSlash[], taskId)executes slashing and returns seized collateral. - For each collateral token:
- if it already equals
payoutToken: transfer directly to beneficiary (surplus forwarded viaPremiumManager.forwardRewardstoRewardsManager), - otherwise: swap through
SwapperusingquoteSwap-derivedamountOutMin; surplus forwarded viaPremiumManager.forwardRewardstoRewardsManager.
- if it already equals
No USD conversion or ChainlinkPriceFeed is used in the claim execution path.
Role: Immutable-style mapping of (coverPool, specId) to ISpec, with admin-controlled spec approval.
Pattern and state:
- UUPS upgradeable proxy.
- Registration is idempotent for the same target and rejects remapping to a different spec.
- Enforces caller is a factory-created pool.
- Maintains an admin-approved whitelist of
ISpecimplementation addresses. A spec must be approved before any pool can register it.
Key functions:
-
approveSpec(spec)called by admin to whitelist a trustedISpecimplementation. -
revokeSpec(spec)called by admin to remove anISpecfrom the whitelist. -
isSpecApproved(spec)view helper to check whether a spec is currently approved. -
registerSpec(specId, spec)called by pool during bind; reverts withSpecNotApprovedif the spec is not on the whitelist. -
resolveSpec(pool, specId)called byClaimManager; resolution is not gated by approval status so in-flight claims on existing policies are unaffected by revocations.
Role: Controlled token conversion path for claim collateral.
Pattern and state:
- UUPS upgradeable proxy.
- Route registry keyed by
(tokenIn, tokenOut). - Supports whitelisted swap targets and native wrapper semantics.
Key functions:
-
setSwapRoute(...),setSwapTargetWhitelist(...)for configuration. -
executeSwap(params)for authorized executors (typicallyClaimManager).
Key roles:
-
SWAP_MANAGER_ROLEconfigures routes and whitelisted targets. -
SWAP_EXECUTOR_ROLEcallsexecuteSwap(held byClaimManager).
Role: Bridges the Swapper's static-calldata pattern to Uniswap V3 SwapRouter02.
Why it exists: The Swapper stores one static calldata blob per (tokenIn, tokenOut) route and
replays it verbatim on every swap. Uniswap V3's exactInputSingle requires the amountIn to be
encoded in each call, making a direct route impossible. The adapter resolves amountIn dynamically
from the allowance the Swapper grants it.
Integration pattern (called by Swapper._performSwap):
- Swapper approves adapter for
amountInoftokenIn. - Swapper calls
adapter.swap(tokenIn, tokenOut, fee, amountOutMinimum)via stored static calldata. - Adapter reads
allowance(Swapper, adapter)to obtainamountIn. - Adapter pulls
tokenInfrom Swapper viatransferFrom. - Adapter calls
SwapRouter02.exactInputSingleforwardingamountOutMinimumfor router-level slippage enforcement. - Router delivers
tokenOutdirectly to Swapper. - Adapter clears residual approval to the router.
Slippage protection: The amountOutMinimum parameter is forwarded directly to the Uniswap V3
router, enabling defense-in-depth slippage protection at the adapter level.
Access control: swap() is restricted to the SWAPPER address recorded at construction time.
Only the authorized Swapper contract may invoke the adapter, enforcing the principle of least
privilege. Any third-party call is rejected with UnauthorizedCaller().
Deployment: script/DeployUniswapV3Adapter.s.sol deploys the adapter (passing the SWAPPER
address as a constructor argument), whitelists it in Swapper, and configures the route in one
transaction. Since UniswapV3Adapter is an immutable contract, any change to the adapter requires
deploying a new instance and reconfiguring the Swapper route via setSwapTargetWhitelist +
setSwapRoute.
| Network | SwapRouter02 |
|---|---|
| Sepolia | 0x3bFA4769FB09eefC5a80d6E87c3B9C650f7Ae48E |
| Mainnet | 0x68b3465833fb72A70ecDF485E0e4C7bD8665Fc45 |
These components live in src/defi/ and are first-class architecture actors.
- UUPS-upgradeable ERC-4626 vault that wraps a Morpho V2 vault,
- accrues premiums continuously against depositor principal via a reward-per-token accumulator,
- exposes
collectPremium()(permissionless) which flushes accrued premium toPremiumManager.distributePremium(), - detects shortfall on withdrawal by comparing
insuredBasis(principal minus paid premium) against proceeds from the Morpho vault, - calls
ClaimManager.fileClaim(...)atomically during withdrawal when a shortfall exists, - receives claim payout and tops up the user's withdrawal to make them whole.
All major contracts are UUPS upgradeable (except CoverPool clones, which are minimal proxies).
Typical control planes:
-
DEFAULT_ADMIN_ROLEfor contract-wide configuration and upgrades. - specialized roles for restricted entrypoints:
-
CREATOR_ROLEon factory, -
QUOTE_SIGNER_ROLEon pools, -
SWAP_MANAGER_ROLE/SWAP_EXECUTOR_ROLEon swapper.
-
- On
SpecRegistry,DEFAULT_ADMIN_ROLEadditionally controls the spec approval whitelist (approveSpec/revokeSpec). Only admin-approvedISpecimplementations may be registered by cover pool curators.
Coverage contracts rely on Core interfaces:
-
IStakeManagerfor committee create/operator/vault and stake reads, -
IRewardsManagerfor reward fan-out trigger, -
ISlashingManagerfor committee slashing execution, -
IChainlinkPriceFeedfor stake-to-USD conversion at bind time (stake sufficiency check inPolicyManager).