Skip to main content
See /concepts/lifecycle for the end-to-end flow (policy → trigger → bond → wait/sell decision).
A Shield is one parametric product. In V5.4 Lumina ships 6 active flash-crash shields (3 BTC + 3 ETH), and every one of them runs the same slim BaseFlashShield logic. The differences between products are just parameters: covered asset, drop threshold, and time window.

The 6 V5.4 products

ProductTriggerWindowPremium /$1k cover
Flash BTC 1hBTC drops ≥ 2.5% from purchase price1 h$2.92
Flash BTC 24hBTC drops ≥ 6% from purchase price24 h$52.60
Flash BTC 48hBTC drops ≥ 10% from purchase price48 h$148.67
Flash ETH 1hETH drops ≥ 4% from purchase price1 h$1.68
Flash ETH 24hETH drops ≥ 8.5% from purchase price24 h$45.80
Flash ETH 48hETH drops ≥ 14% from purchase price48 h$123.01
Shared parameters across all 6 products:
ParameterValue
Deductible20%
Payout ratio80% (= 800faceper800 face per 1,000 cover)
Bond maturity730 days
Margin multiplier2.00x (effective premium multiplier ≈ 1.60x after deductible)
OracleChainlink BTC/USD + ETH/USD on Base mainnet
Bond face$1 per token
Discover the live set with GET /products or lumina.products.list().

V5.4 addresses (Base mainnet)

Each product is reached via its FlashShieldAdapter (the address PolicyManagerV2.productShield(productId) returns). The adapter delegates to the underlying slim BaseFlashShield. See Adapters for why the two-layer pattern exists.
ProductAdapter (the one PM points to)BaseFlashShield
Flash BTC 1h0x5d50310B9166184e822cD5368F51C1409713054f0x7d1615C90d01712a3b86Df26312aC6D8EFa0d0b3
Flash BTC 24h0x475b3F712707F61824122a94fE78b106260F88820x18e2D3b8Ff4D194CDB9862f8e6239E5e1145961d
Flash BTC 48h0xdc6387E86F7D852D1f99F4009cFd8AdC2d5002980xe206dd8fb02b1C2A0507566c3d03a27554E8CBeB
Flash ETH 1h0x57869AD3E7C56B0c96F357179DD231b407C883380xfF1a1B20153019C22f97278204Ccfc1b1409a518
Flash ETH 24h0x4fD09cF98F6814Cc8b33C2E491429f59d0bCf0890x2832b5543f6F2a055312654739F0ae03F5b0b582
Flash ETH 48h0x9696CFFD7dE8B1e16F83Dcc798c5CE69a61C884C0x60dFC6610c64aC84e12afA943737Cf7733215B75

Shape

FieldMeaning
productId (bytes32)keccak256(canonicalName) — e.g. keccak256("FLASHBTC1H-001")
payoutRatioBpsCents-on-the-dollar paid out when triggered (8000 = 80%)
marginBpsSafety margin built into premium pricing
durationSecondsCoverage window length (1h / 24h / 48h)
activeWhether new policies can be purchased

How BaseFlashShield gates a trigger

Every shield runs the same five checks in submitTrigger(payload, signature):
  1. Oracle signature. EIP-712 payload must be signed by LuminaOracleV2.oracleKey().
  2. 3 confirmations 60s apart. The oracle internally reads the Chainlink feed 3 times, at least 60 seconds between reads, and aggregates. A single spike won’t trigger; the move has to persist across the read window.
  3. L2 sequencer uptime. Reads Base’s Chainlink L2 sequencer uptime feed; if the sequencer is reported down or in grace period, triggers are rejected (no triggering during outages where users couldn’t react).
  4. Strike snapshot at purchase. Each policy stores the asset’s price at purchase time as the strike. The drop is measured against the strike — never against an arbitrary trailing peak or future price.
  5. Drop and window. Accept if (strike - currentPrice) / strike ≥ TRIGGER_DROP_BPS and block.timestamp ≤ policy.startedAt + durationSeconds.
On accept, the shield calls BondVault.mint(buyer, faceValueUsd) — the buyer receives an ERC-1155 ClaimBond with 800faceper800 face per 1,000 cover, 730-day maturity. No “claim” step is required.

The “drop from purchase price” mechanic

A common point of confusion: the drop is always measured against the strike snapshotted at purchase, not against a daily open, a TWAP, or the all-time high. Two consequences:
  • Buying right before a recovery is worthless — if BTC drops 2.6% from your strike a minute after you buy, you trigger. If it drops 2.6% from someone else’s strike but only 0.3% from yours, you don’t.
  • The strike persists for the full window. Multiple buyers of the same product at different times will have different strikes and may trigger on the same price move (or not), depending on each one’s strike.

Verifying a productId yourself

import { keccak256, toUtf8Bytes } from 'ethers'
keccak256(toUtf8Bytes('FLASHBTC1H-001'))
The productId is a 32-byte hash, not an address.

See also