Protocol Documentation · Base Mainnet

What is
SentinelShield?

A decentralized insurance protocol for DeFi. Smart contract coverage backed by Aave V3 yield, adjudicated by on-chain DAO governance, and settled automatically by a keeper-pattern executor. No servers. No databases. No intermediaries.

DeFi has no safety net.

Smart contracts hold billions of dollars in user assets, and smart contracts get exploited. Reentrancy attacks, oracle manipulation, flash-loan price attacks, governance takeovers — the attack surface grows with every new protocol composing on top of another. When an exploit lands, users lose funds with no recourse. There is no FDIC for DeFi. There is no chargeback.

Existing DeFi insurance solutions suffer from three recurring problems: idle capital that earns nothing, centralised claim adjudication that can be captured, and opaque premium models that users cannot verify. SentinelShield was built to solve all three simultaneously.

"Every dollar of collateral earns Aave V3 yield while it waits. Every claim is adjudicated by token-weighted governance that cannot be flash-loan-attacked. Every premium calculation is a pure function that anyone can verify."

The result is a composable insurance layer that any DeFi protocol, DAO, or individual position can plug into — protocol-native coverage with zero trusted intermediaries, zero idle capital, and fully on-chain settlement from first claim filing to final USDC payout.

Three roles. One protocol.

SentinelShield has three participant types, each interacting with a different layer of the protocol stack:

Policyholders

DeFi users or protocols that purchase coverage against smart contract exploits. They pay a one-time premium, receive a soulbound PolicyNFT, and can file a claim if the covered protocol is exploited while their policy is active.

Liquidity Providers

Capital providers who deposit USDC into the CoveragePool. Their capital earns Aave V3 base yield plus a share of protocol premiums. In exchange, their capital backs active policies and may be partially drawn down if a claim pays out.

SHIELD Holders

Governance participants who hold $SHIELD tokens and vote on claim outcomes. They examine evidence submitted by claimants and vote yes or no within the 7-day window. Their historical balance at the snapshot block determines their voting weight.

Three isolated layers.

The protocol is split across three execution layers that share no state variables with each other. A critical bug in the governance layer cannot drain the capital vault. A misconfigured PolicyEngine cannot override a veto. The separation is structural, not conventional.

System Layers — Top to Bottom
USER / DAPPwagmi v2 · viem · RainbowKit · any EOA
POLICY ROUTINGPolicyEngine · RiskRegistry · PolicyNFT (ERC-5484)
CAPITAL UNDERWRITINGCoveragePool (ERC-4626) · Aave V3 Pool · aUSDC
ADJUDICATIONClaimsGovernor · ShieldToken (ERC-20Votes) · VetoCouncil
SETTLEMENTPayoutExecutor (Keeper-callable)

The key invariant: CoveragePool only accepts liquidity operations from PolicyEngine, and payout operations from PayoutExecutor. Neither ClaimsGovernor nor VetoCouncil can touch the underlying USDC directly — they can only update claim state. Actual fund movements require passing through CoveragePool's authorised caller checks.

Every contract. What it does. Why it exists.

No contract in this system is ceremonial. Each one solves a specific problem that could not be solved by any other contract in the stack.

01
⚙️

PolicyEngine

CEI · NonReentrant
The brain of policy issuance

PolicyEngine is the central orchestration hub of SentinelShield. Every time a user buys coverage, this contract runs the entire atomic transaction — it validates the protocol against the RiskRegistry, checks that the pool has sufficient free liquidity, calculates the exact premium via PremiumMath, pulls USDC from the buyer, routes it to the CoveragePool as yield, locks the coverage collateral, and mints a soulbound PolicyNFT to the buyer's wallet — all within a single EVM execution frame that either succeeds completely or reverts cleanly. The payable modifier is present purely to bypass an EVM gas optimisation constraint; no ETH is ever accepted.

One architectural decision worth noting: the ClaimsGovernor address is write-once — it can only be set by the owner once and can never be changed. This means that once the system is live, PolicyEngine's connection to governance is permanent and immutable, preventing any future owner from routing claim adjudication to a malicious contract.
Basescan · 0xEF80…5564
02
🏦

CoveragePool

ERC-4626 · Aave V3
The capital vault

CoveragePool is where the money lives. It is a fully ERC-4626 compliant vault with one critical modification: every deposit is immediately forwarded to Aave V3 Base Core, where it earns continuous yield for liquidity providers. The vault tracks two separate buckets of USDC — "free" liquidity that is available for new policies or LP withdrawals, and "locked" liquidity that has been reserved as collateral for active policies. These two buckets are enforced at the mathematical level: the _withdraw hook reverts if a withdrawal would eat into locked collateral.

The decimals offset of 6 is a deliberate inflation-attack mitigation. Since USDC only has 6 decimals, the vault applies a 10^6 virtual share multiplier so that the first depositor cannot manipulate the share price by donating dust. This is OpenZeppelin's recommended approach for ERC-4626 vaults with low-decimal underlying assets.
Basescan · 0x374d…c3eD
03
📋

RiskRegistry

Ownable2Step · Pausable
The source of truth for risk

RiskRegistry is the on-chain database that defines what can be insured and at what cost. Every protocol that SentinelShield covers must be registered here with a risk score between 0 and 100, an audit status flag, and a coverage cap. The risk score directly feeds into PremiumMath — a protocol scoring 80 pays a premium roughly 2.6x higher than one scoring 30. The audit status gives a flat 20% discount on top of the risk-score calculation. The coverage cap prevents any single protocol from consuming the entire pool.

The blacklist mechanism is deliberately asymmetric with the pause. Pausing halts all registry management operations. But blacklisting a protocol — which prevents new policies being issued for it — ignores the pause state. This is intentional: if a protocol suffers an exploit and the owner needs to halt new coverage immediately, they should not be blocked by an administrative pause.
Basescan · 0x049C…53DB
04
⚖️

ClaimsGovernor

Snapshot Voting · Flash-Loan Resistant
The adjudication machine

ClaimsGovernor is where a filed claim lives and dies. When a policyholder submits a claim with IPFS or Arweave evidence, the contract takes an immutable snapshot of SHIELD token balances at block.number - 1. This historical checkpoint is the key flash-loan defence: any attacker who borrows SHIELD tokens in the same block as the claim filing will find their borrowed balance was not present at the snapshot block and therefore carries zero voting weight. The 7-day voting window then opens, during which any wallet with historical SHIELD balance can cast a token-weighted vote.

The VetoCouncil address and PayoutExecutor address are both write-once configurations here as well. Once set, neither can be changed. This makes the protocol's emergency override path permanent — the set of guardians who can veto a fraudulent claim cannot be silently swapped out after the fact.
Basescan · 0xB793…2Ba3
05
🛡️

ShieldToken

ERC-20Votes · EIP-712
The governance token

ShieldToken ($SHIELD) is the voting backbone of the entire protocol. It implements ERC20Votes — the OpenZeppelin extension that enables historical balance checkpointing — which is what makes flash-loan-resistant governance possible. Holders must delegate their votes to themselves or another address before their balance counts. This is a standard ERC-20Votes requirement: holding tokens without delegating means zero voting power. The token is capped at 100 million SHIELD total supply with no inflation mechanic — only the owner can mint, and only up to the hardcoded cap.

The EIP-712 Permit extension allows gasless approvals via signature. For governance contexts, this means a holder can authorise a third party to vote on their behalf without needing to pay gas for the approval transaction. Combined with ERC20Votes' getPastVotes(), this creates a clean delegated voting stack.
Basescan · 0xafE2…a2d1
06
🔒

VetoCouncil

M-of-N Multisig · Emergency Circuit
The emergency safety valve

VetoCouncil is the last line of defence against sophisticated governance attacks or fraudulent claims that somehow acquired enough SHIELD votes to pass. It implements an M-of-N multisignature pattern: a configurable set of guardians can each sign a veto proposal for any pending claim, and once the signature count meets the threshold, the veto is automatically executed against ClaimsGovernor. Crucially, a veto can only be applied while a claim is still PENDING — it cannot retroactively undo an already-executed payout. This makes the VetoCouncil a circuit breaker, not a rug mechanism.

The CEI pattern is applied even within the veto execution: the VetoExecuted event is emitted before the external call to ClaimsGovernor.vetoClaim(). This prevents any theoretical reentrancy into the VetoCouncil's own state from an untrusted ClaimsGovernor, even though the current ClaimsGovernor is trusted.
Basescan · 0x8966…92B0
07
🖼️

PolicyNFT

ERC-5484 Soulbound · On-chain SVG
The soulbound policy receipt

PolicyNFT issues one non-transferable ERC-721 token per purchased policy. The soulbound enforcement is implemented at the lowest possible level — the _update() hook in OpenZeppelin's ERC-721 v5 base. Any call that would move a token from one non-zero address to another non-zero address is unconditionally reverted. This cannot be bypassed by any external call path because _update() is the single choke point for all ERC-721 balance mutations. The token's metadata — including a rendered SVG badge showing the policy status, protocol, coverage amount, and expiry — is generated entirely in Solidity by PolicyNFTSVG and returned as a Base64 data URI directly from tokenURI().

The ERC-4906 MetadataUpdate event is emitted whenever a policy status changes — when it expires, is claimed, or is cancelled. Any marketplace or dashboard that implements ERC-4906 will automatically refresh the token's displayed artwork when this event fires, without any off-chain intervention.
Basescan · 0x02A9…1C00
08
💸

PayoutExecutor

Keeper Pattern · CEI
The payout execution engine

PayoutExecutor is a deliberately simple contract with exactly one job: execute a USDC payout when a claim has been formally approved by governance. It is callable by anyone — there is no privilege in triggering a payout, because the democratic process has already completed. Any keeper, bot, or manual user can call executePayout() for an APPROVED claim. The contract reads the claim from ClaimsGovernor, reads the policy details from PolicyEngine, verifies the payout amount does not exceed the locked collateral, marks the claim as EXECUTED in ClaimsGovernor first (CEI), then instructs CoveragePool to withdraw the USDC from Aave and send it directly to the claimant.

The CEI application here is particularly important. By marking the claim as EXECUTED before calling CoveragePool, any reentrancy back into PayoutExecutor would find the claim status is EXECUTED, not APPROVED, and would revert. This means the payout can only ever be sent once regardless of how the external call behaves.
Basescan · 0x897a…50A7

Transparent. Verifiable. Pure.

PremiumMath is a stateless Solidity library — zero storage reads, zero external calls, zero reentrancy surface. It is a pure function that takes four inputs and returns one output: the exact premium in USDC. Because it is a pure library function, anyone can call it off-chain in advance and get the identical result that the contract will produce at purchase time.

BASE FORMULA
premium = (coverageAmount × BASE_RATE_BPS × riskScore × duration)
/ (100 × 10,000 × 365 days)
if audited: premium × (1 − 0.20)
min(premium, 1 USDC)

BASE_RATE_BPS is 1,000 basis points (10% APR) at maximum risk score of 100. A protocol scored 50 pays half that annualised rate. Duration scales linearly — a 30-day policy costs roughly 1/12 of a 365-day policy at the same coverage level. The 20% audit discount rewards protocols that have demonstrated security diligence. All arithmetic is multiply-before-divide to avoid Solidity integer truncation errors.

The refund function is equally simple: pro-rated by remaining time. If you cancel a 365-day policy after 180 days, you receive (185/365) × premium back. The refund goes into a pending-pull balance rather than being pushed immediately — this eliminates DoS vectors where a malicious policy contract could block the refund transfer.

The rules of valid claims.

ClaimValidator is a pure library that encodes all governance validation rules in one place. ClaimsGovernor calls into it for every claim and vote operation. This separation means the validation rules can be read, audited, and verified independently of the governor's state management logic.

validateClaimEligibility()

Checks that the policy status is ACTIVE (status == 0), that the current timestamp has not passed expiresAt, and that the caller is the policy holder. Three separate reverts for three separate failure modes — frontends can show the user exactly why their claim was rejected.

validateEvidence()

Enforces a minimum URI length of 10 characters. Rejects empty strings and suspiciously short inputs that would not constitute real IPFS or Arweave URIs. Two distinct errors distinguish empty from too-short for cleaner frontend error handling.

isClaimApproved()

Computes the 1% quorum threshold: (totalSupply × 100) / 10,000. If total votes (yes + no) do not meet this threshold, the claim fails regardless of vote distribution. If quorum is met, yes votes must strictly exceed no votes. Both conditions must hold simultaneously.

computeVoteWeight()

Currently a pass-through that returns the raw SHIELD balance from the snapshot. Architecturally isolated here so that future voting mechanisms — quadratic weighting, delegation multipliers, veToken curves — can be implemented by upgrading this single function without modifying ClaimsGovernor.

Art that lives on the blockchain.

PolicyNFTSVG is a pure Solidity library that generates the complete SVG artwork for every PolicyNFT — character by character, inside the EVM. There is no IPFS. No external server. No Arweave gateway that can go offline. The SVG is constructed from string concatenation in Solidity, base64-encoded by OpenZeppelin's Base64 library, and returned as a data URI directly from tokenURI(). The token's art exists as long as Ethereum exists.

The SVG reflects the policy's current state in real time. Every tokenURI() call reads the policy's current status from PolicyNFT's storage and renders the appropriate badge color: green for ACTIVE, grey for EXPIRED, blue for CLAIMED, red for CANCELLED. As a policy transitions states — expiring, being claimed, being cancelled — the rendered artwork changes automatically on every metadata query. No re-minting. No gas cost. No owner action required.

The library uses block scoping (curly braces) throughout its internal functions to avoid Solidity's stack-too-deep compiler error, which surfaces when a function references more than 16 local variables. This is a production-grade pattern for complex on-chain SVG generation and demonstrates the same approach used by on-chain generative art projects like Loot.

"A PolicyNFT is not a static image. It is a live window into the current state of your on-chain insurance position, rendered by the blockchain itself."

From purchase to payout. Every step.

01
Risk assessment and quoting
A user selects a registered DeFi protocol and a coverage amount between $100 and $1,000,000 USDC. PolicyEngine calls quotePremium(), which reads the protocol's risk score and audit status from RiskRegistry and runs it through PremiumMath. The formula: (coverageAmount × BASE_RATE_BPS × riskScore × duration) / (100 × 10,000 × YEAR_SECONDS), with a 20% discount for audited protocols and a minimum of 1 USDC. The premium is a single one-time payment — no recurring costs.
02
Policy purchase and collateral locking
The buyer approves the premium amount and calls buyPolicy(). PolicyEngine verifies eligibility, computes the premium, pulls USDC from the buyer, routes it to CoveragePool as yield-earning premium income, instructs CoveragePool to lock the coverage amount as reserved collateral, and mints a PolicyNFT (ERC-5484 Soulbound) to the buyer's wallet. The locked USDC immediately starts earning Aave V3 yield while backing the policy. All of this happens in a single atomic transaction.
03
Exploit event and claim filing
If the covered protocol suffers an exploit, the policyholder calls ClaimsGovernor.fileClaim() with an IPFS or Arweave URI containing exploit evidence — transaction hash, post-mortem, amount lost. The contract takes an immutable snapshot of SHIELD token balances at block.number - 1 (the flash-loan defence), opens a 7-day voting window, and emits ClaimFiled. The policy cannot be cancelled while a PENDING claim is active.
04
Token-weighted governance vote
During the 7-day window, any SHIELD holder with historical balance at the snapshot block can call castVote(claimId, true/false). Voting power is proportional to historical token balance. Double-voting is prevented by a per-claim-per-address flag. After the window closes, anyone can call finalizeClaim(). The claim passes if total votes reach the 1% quorum threshold and yes votes exceed no votes. Failed quorum or majority-no results in REJECTED status.
05
VetoCouncil intervention (if needed)
At any point while a claim is PENDING, the VetoCouncil can veto it if a threshold of guardian signatures is collected. A veto permanently cancels the claim and prevents payout. This is the emergency circuit for provably fraudulent claims — coordinated fake exploits, spam claims, or edge cases where governance was genuinely gamed despite the flash-loan protections. Once APPROVED or beyond, the veto can no longer be applied.
06
Payout execution
Once a claim reaches APPROVED status, any external actor can call PayoutExecutor.executePayout(claimId). The executor verifies the claim is APPROVED, reads the coverage amount from PolicyEngine, marks the claim EXECUTED (CEI — before the external call), then instructs CoveragePool to withdraw the exact coverage amount from Aave V3 and transfer it directly to the policyholder's wallet. The payout cannot be triggered twice because the EXECUTED status check prevents re-entry.

Why it was built this way.

01
Separation of concerns taken seriously

SentinelShield's architecture deliberately separates three concerns that DeFi protocols routinely conflate: capital management, policy administration, and governance adjudication. The CoveragePool knows nothing about policy terms — it only knows how much USDC is locked per policy ID. The PolicyEngine knows nothing about claims voting — it only knows whether a policy is active. The ClaimsGovernor knows nothing about USDC movements — it only manages claim state transitions. A bug in one layer cannot cascade into another because there are no shared state variables between contracts.

02
Flash-loan resistance is not optional

Most DeFi governance protocols are vulnerable to flash-loan governance attacks: borrow a large amount of governance token in a single transaction, vote, repay. SentinelShield closes this vector at the source. ClaimsGovernor queries SHIELD balances using getPastVotes(voter, snapshotBlock) where snapshotBlock is block.number - 1 at the time of claim filing. Tokens borrowed in the current block do not appear in any historical checkpoint. A flash loan that buys voting power in block N cannot vote on a claim filed in block N because the snapshot was taken at block N-1. This protection is cryptographically guaranteed by ERC-20Votes checkpoint mechanics, not by any custom logic.

03
Write-once addresses prevent silent upgrades

Every cross-contract address configuration in SentinelShield follows the same pattern: a boolean flag, a one-time setter, and a revert if called twice. PolicyEngine's ClaimsGovernor, CoveragePool's PolicyEngine, CoveragePool's PayoutExecutor, ClaimsGovernor's VetoCouncil, ClaimsGovernor's PayoutExecutor, PolicyNFT's PolicyEngine — every single wiring point is permanently set at deployment time and provably immutable thereafter. A compromised owner private key cannot silently reroute claims to a malicious adjudicator or redirect payouts to an attacker-controlled pool, because the routing addresses are already final.

04
No idle capital, ever

A decentralised insurance protocol that parks USDC in a mapping is economically inefficient — the capital earns nothing while backing active policies. SentinelShield routes 100% of deposited USDC to Aave V3 the moment it enters the pool. Premiums collected from policy purchases are also immediately supplied to Aave. Even locked collateral earns aUSDC yield while it sits backing an active policy. LPs receive a yield stream from two sources simultaneously: Aave's base lending APY, and protocol premium flow. The share price of ssUSDC grows continuously even between policy purchases.

05
CEI is applied without exception

Every state-changing function in every contract follows the Checks-Effects-Interactions pattern without exception. Checks come first: validate inputs, verify caller permissions, confirm state preconditions. Effects come second: write all storage mutations before touching any external address. Interactions come last: external calls to other contracts, token transfers, Aave supply/withdraw operations. Reentrancy guards are applied on top of CEI as a belt-and-suspenders redundancy. The guards are present not because CEI has a gap, but because CEI is a manual guarantee that a single careless future modification could break — the guard makes it mechanical.

06
Soulbound identity for real-world coverage semantics

Insurance policies in the physical world are not tradeable assets. They are agreements between a specific insured party and an underwriter that a specific position will be covered. PolicyNFT enforces this semantic on-chain: a policy token minted to wallet A cannot be sold to wallet B, cannot be gifted, cannot be used as DeFi collateral. The policy covers exactly the wallet that purchased it, for exactly the protocol and amount specified at purchase time. The soulbound enforcement is not a soft social norm — it is a hard EVM revert on every transfer attempt. The only movements allowed are minting (address(0) → holder) and burning (holder → address(0)).

Designed to be attacked. Built to hold.

The protocol was statically analysed with Slither v0.10.x against the full Foundry artifact matrix. Zero high-severity findings. Two medium findings were reviewed as false positives — the payable modifier on buyPolicy() is an intentional EVM gas optimisation, not an ETH acceptance bug.

LevelCountStatusNotes
Critical0Absolute zeroNo exploit windows detected in any execution path.
High0ClearNo structural data-leakage or state corruption vectors.
Medium2False positivespayable optimisation on buyPolicy(). Reviewed and documented.
Low11Standard patternsSafeERC20 wrappers manage low-level transfer safety uniformly.
Info16NatSpecAll documented with structured inline signatures.
Security Invariants
CEI everywhere
Checks-Effects-Interactions enforced without exception across all 8 contracts. All storage mutations precede external calls.
Reentrancy guards belt-and-suspenders
All state-changing functions carry nonReentrant modifiers as a redundant mechanical layer on top of CEI.
Write-once addresses
Every cross-contract routing address is immutable after first configuration. No owner key compromise can silently reroute funds.
Flash-loan resistant voting
Historical checkpoint queries (getPastVotes at block.number - 1) guarantee borrowed tokens carry zero weight.
Soulbound transfer lock
_update() override in PolicyNFT reverts any non-zero to non-zero token movement unconditionally.
Free/locked liquidity accounting
totalLiquidity = freeLiquidity + totalLockedLiquidity enforced at every deposit, withdrawal, lockCoverage, releaseCoverage, and executePayout call.
Integer arithmetic precision
PremiumMath uses multiply-before-divide throughout. No precision loss from early division.
Payout uniqueness
PayoutExecutor marks claim EXECUTED before calling CoveragePool. Any reentry attempt finds EXECUTED status and reverts.
⚠ Audit Disclaimer

These contracts implement production-grade security patterns and were self-audited by the author using Slither and manual review. They have not undergone a formal external security audit by a professional firm. Do not deploy to mainnet with material funds without engaging a qualified smart contract auditing firm. This is a production deployment on Base Mainnet.

Live on Base Mainnet.

All contracts are verified and publicly readable on Basescan. Interact with proxy addresses where applicable.

PolicyEngine
Core
0xEF80cd6370D4619D2f71BD4000a4757357Be5564
Basescan ↗
CoveragePool
Core
0x374d949c7A575212d423Ecc0e765a59664d7C3eD
Basescan ↗
RiskRegistry
Core
0x049C2eC773cDa5F3a19F9cc7C67D3331C21853DB
Basescan ↗
ClaimsGovernor
Governance
0xB7939f8b41C932595cf358842BC63AFE221D2Ba3
Basescan ↗
ShieldToken ($SHIELD)
Governance
0xafE2B560ad1743DA67BdA1850aF47CdB2280a2d1
Basescan ↗
VetoCouncil
Governance
0x896627825AEAc934e4CAec4cb00EC8B90a5292B0
Basescan ↗
PolicyNFT
Token
0x02A9E50D9EB6fec67c419C5ddb3ffd894DD01C00
Basescan ↗
PayoutExecutor
Execution
0x897a76eC710DC780E4627532A0e863F2672d50A7
Basescan ↗
Circle USDC (Collateral)
External
0x833589fCD6eDb6E08f4c7C32D4f71b54bda02913
Basescan ↗
Aave V3 Pool (Base Core)
External
0xA238Dd80C259b705191C65851448bB1e2D3b3790
Basescan ↗

Ready to use
the protocol?

Connect your wallet, purchase coverage, or provide liquidity. Everything runs on Base Mainnet.

Base Mainnet · MIT License · Built by NexTech Architect