Skip to content

Repository files navigation

Backstop logo — open the live app

Backstop 🛟

Redemption insurance for FXRP — if your redemption agent never delivers XRP, Flare's own on-chain proof pays you make-whole

Backstop — open the live app

Live Web AppPitch DeckYouTube DemoFDC Gate PASSEDReal Claim PAIDDeployed on Coston2Flare Summer SignalDoraHacks BUIDL


SolidityFoundryNext.jsTypeScriptTestsCoverageLicenseCI/CDRelease


⚠️ The problem

FAssets let XRP holders bring their asset into Flare DeFi — but the redemption leg (turning FXRP back into native XRP) is the riskiest step. When you redeem, an assigned agent must send you XRP by a deadline. If it doesn't, you have to notice the miss, commission a Flare Data Connector proof yourself, call redemptionPaymentDefault(), and accept collateral compensation at a haircut. It's manual, slow, and uncertain — and that uncertainty keeps desks and treasuries from redeeming at size, quietly weakening confidence in the FXRP peg.

🛟 The solution

Backstop turns that into a one-click guarantee. You buy a guard bound to your on-chain redemption ticket for a small FTSO-priced premium. An autonomous keeper watches the deadline. If the agent doesn't pay, anyone can submit Flare's FDC ReferencedPaymentNonexistence attestation — the exact proof the FAssets protocol itself accepts for a redemption default — and Backstop verifies it on-chain and pays you make-whole instantly. Underwriters fund the pool and earn the premiums of every guard whose agent paid on time.

Backstop doesn't re-invent cross-chain trust — it rides Flare's own default mechanism.

👤 Who it's for

  • Primary — the FXRP redeemer. Anyone converting FXRP back to native XRP through the FAssets redemption queue, and especially trading desks and treasuries redeeming at size, for whom a single agent default is a real balance-sheet event. Concretely: the wallet that calls AssetManager.redeem() and then has to wait and hope the agent delivers on XRPL.
  • Secondary — the underwriter (LP). FLR holders wanting yield uncorrelated with token price. They fund the pool, earn redemption premiums, and are protected by an on-chain per-agent exposure cap and a global solvency cap.
  • Downstream — FAssets integrators. Lending markets, DEXes and custodians that would rather quote FXRP redemption risk than absorb it. buyGuard is callable by any contract — Backstop is a protocol, not just an app.

🔥 Why this needs Flare — and only Flare

Six engine-class Flare methods, wired in code and proven on Coston2:

#Flare methodRole in Backstop
1IFdcVerification.verifyReferencedPaymentNonexistencethe claim gate — proves the agent did NOT pay
2IFdcHub.requestAttestation (RPN)keeper requests the non-payment attestation
3FDC DA-Layer proof fetchretrieves the finalized proof + Merkle path
4IAssetManager.redemptionRequestInfobinds a guard to a real FXRP redemption ticket
5FtsoV2.getFeedById (XRP/USD, FLR/USD)sizes coverage + prices premium/payout
6FlareContractRegistry.getContractAddressByNameresolves everything — nothing hardcoded

Take Flare out and you'd need four separate systems: a cross-chain XRPL light client, a decentralized "payment-did-not-happen" attestation network, a price oracle, and a canonical FXRP redemption registry. Backstop is ~550 lines of Solidity because Flare enshrines all four — and FDC's non-existence proof is something almost no other chain exposes natively.

🏗️ Architecture

flowchart TD
U[Redeemer] -->|redeem FXRP| AM[FAssets AssetManager]
U -->|buyGuard ticket + premium| BS[Backstop]
LP[Underwriters] -->|deposit / withdraw| POOL[BackstopPool]
BS <-->|lock exposure · payout| POOL
BS -->|getFeedById XRP/USD · FLR/USD| FTSO[FtsoV2]
BS -->|redemptionRequestInfo| AM
K[Keeper ⏱] -->|watch deadline| AM
K -->|requestAttestation RPN| HUB[IFdcHub]
HUB --> RELAY[Relay · Merkle root]
K -->|fetch proof| DA[DA Layer]
K -->|claim guardId, proof| BS
BS -->|verifyReferencedPaymentNonexistence| FDCV[IFdcVerification]
BS -->|make-whole payout| U
FE[Web · /integrations/verify] -->|live reads| BS
FE -->|live reads| POOL
classDef flare fill:#0B7A57,stroke:#3ECF9A,color:#fff;
class AM,FTSO,HUB,RELAY,DA,FDCV flare;
Loading

Contracts resolve every Flare address through the registry (RegistryResolver); the keeper is a convenience, not a trust assumption — the claim path is permissionless, so the redeemer or anyone can submit the proof.

🔁 The one flow

buyGuard → agent misses deadline → keeper requests RPN proof → claim verifies it on-chain → make-whole payout

buyGuard premium re-pricing live from FTSO as coverage changes
buyGuard (wallet connected): the premium re-prices live from the FTSO FLR/USD feed as you type — $0.70 → 1.2281 C2FLR, $2.50 → 4.386 C2FLR.

✅ Proof: the Day-4 FDC gate (PASSED)

The whole product hinges on one assertion: that the FDC non-existence round-trip actually works on Coston2. We front-loaded it as a go/no-go gate — scripts/spike.ts exercises every load-bearing call-site end-to-end and prints PASS/FAIL. Run npm run spike:view (no wallet) or npm run spike:all (funded).

✅ PASSED on Coston2 (2026-07-29). All five stages green. The load-bearing leg — IFdcHub.requestAttestation → DA-Layer proof → IFdcVerification.verifyReferencedPaymentNonexistence — returned true on-chain in 99.3 s (tx 0x5774a763…9c540a, voting round 1409442). Full benchmark + reproduce steps: DEMO.md.

✅ Proof: a real end-to-end claim (PAID, on-chain)

Beyond the isolated FDC gate, the entire product loop ran live on Coston2 against a genuine FAssets redemption defaultredeembuyGuard → the assigned agent misses the deadline → keeper proves non-payment via FDC → claim pays the redeemer make-whole:

✅ Guard #1 PAID (2026-08-01). Real ticket redemptionRequestId 42481292 (agent 0xd5dE…2D64). The keeper reconstructed the ReferencedPaymentNonexistence window directly from the live redemptionRequestInfo — its primary path, not the synthetic fallback — and Backstop.claim paid 111.55 C2FLR to the redeemer. Claim tx 0x5fde024f… (block 33493034). Full tx trail + one-command reproduce (npm run route-b): DEMO.md · scripts/route-b.ts.

/integrations/verify reading live Coston2 state: guard #1 PAID and the claim payout card
/integrations/verify, live from Coston2 — guard #1 PAID, payout 111.55 C2FLR at block 33493034 (no wallet needed).

🚀 Deployed on Coston2 (chain 114) — verified source

ContractAddress
Backstop0xe7DFfa49EC57f5a9ca349C0F9a170950F052E708
BackstopPool0x9c1e0f1318141B7dA85207d731157D4853918A9A

Both source-verified on Blockscout — the exact repo source, including the reentrancy guards and zero-address checks (Slither: 0 findings). Deploy script: script/Deploy.s.sol.

🧩 Components

LayerWhereWhat
Contractssrc/Backstop (guard lifecycle + claim), BackstopPool (underwriting), PremiumMath, RegistryResolver
Keeperscripts/keeper.tsautonomous watcher — detects breaches, requests the RPN proof, submits claim. --once / --dry-run modes (scripts/KEEPER.md)
Spikescripts/spike.tsthe Day-4 gate harness (stages a–e)
Webweb/Next.js dApp reading live Coston2 state, incl. the /integrations/verify proof route

Both sides of the market, wallet-connected on Coston2:

Buy a guard — live FTSO premiumUnderwrite — live pool position
Buy a guardUnderwrite the pool

🧪 Testing

90 unit tests · 100% line / statement / function coverage across all four contracts (branch coverage 98.7% — the one uncovered branch is a reentrancy-guard revert that Foundry can't credit through the nested re-entry call; the guard itself is exercised by a dedicated test), plus 4 live-Coston2 fork integration tests (test/ForkCoston2.t.sol) against the real registry, FtsoV2, and AssetManager. The fork tests skip automatically when no COSTON2_RPC_URL is set, so offline CI stays green (94 tests with a fork).

forge test# 90 offline · 94 with a Coston2 RPC
forge coverage --no-match-coverage "(script|test)" --summary

Unit tests exercise Backstop's own logic with mock Flare contracts; the real integration is proven by the fork tests + the Day-4 spike — never mocked-as-real.

⚡ Getting started

# Contracts
forge soldeer install # deps
forge build && forge test# compile + test
cp .env.example .env # fill PRIVATE_KEY (throwaway testnet key), fund at faucet.flare.network/coston2# Prove the Flare integration end-to-end on Coston2
npm install && npm run spike:all
# Deploy (Blockscout-verified, no API key)source .env && forge script script/Deploy.s.sol:Deploy \
--rpc-url "$COSTON2_RPC_URL" --private-key "0x$PRIVATE_KEY" --broadcast \
--verify --verifier blockscout --verifier-url https://coston2-explorer.flare.network/api/
# Run the autonomous keeper
npm run keeper:once # single sweep · npm run keeper for the watch loop# Web appcd web && npm install && npm run dev # http://localhost:3000

⚖️ Honest limitations

  • Pool solvency under correlated defaults — many agents failing at once can under-fund the pool; mitigated by a per-agent exposure cap (invariant-tested) and a global solvency cap (total coverage ≤ 80% of the pool's live USD value, FTSO-priced), both enforced on-chain — bounded, not eliminated.
  • Payout latency = FDC round time — make-whole is fast but bounded by the attestation voting round (~99 s measured); we surface the wait in the UI rather than hide it.
  • Linear premium model (base + k·σ) — a deliberate MVP simplification, flagged in code.

🆕 What was newly built during the program

Everything. Backstop did not exist before this hackathon — no prior codebase, nothing ported, nothing carried over. First commit b2fed37 is dated 2026-07-25, inside the program window (development opened June 29, submission closes August 14). The whole history is public and reviewable:

git log --reverse --format="%h %ad %s" --date=short | head
BeforeBuilt during the program
Smart contractsnothing554 lines of Solidity across 4 contracts
Flare integrationnothing6 engine-class methods (FDC ×3, FAssets, FTSO v2, Registry)
Testsnothing94 tests — 90 unit (100% line/stmt/func coverage) + 4 live-fork, plus 128k-call invariant runs
KeepernothingTypeScript/viem autonomous watcher: deadline → RPN request → DA-Layer poll → claim
Web appnothingNext.js App Router frontend incl. the public /integrations/verify proof route
DeploymentsnothingBoth contracts deployed and source-verified on Coston2

Third-party code is dependencies only (flare-periphery, OpenZeppelin, Foundry, viem/wagmi, Next.js) — no application logic borrowed.

Milestones, all on-chain: Day-4 FDC gate passed 2026-07-29 (99.3 s round-trip, round 1409442) · full end-to-end claim 2026-08-01 (guard #1 PAID, 111.55 C2FLR, block 33493034) · contracts hardened and redeployed after clearing all 30 Slither findings.

🗺️ Roadmap

The economics already shipped — live parameters, readable on-chain from the deployed contract:

ParameterLive valueMeaning
baseBips / kBips / sigmaBips100 / 50 / 2000premium = base + k·σ = 110 bips = 1.10% of coverage
agentCapUsd$100,000max exposure to any single agent vault
maxUtilizationBips8000total coverage ≤ 80% of live pool USD value

A desk redeeming $10,000 of FXRP pays $110 to be made whole; the pool holds $1.25 for every $1 of coverage written.

Next, in dependency order:

  1. Calibrate σ against real default history. The 20% volatility figure is an honest MVP placeholder — fit it to measured FAssets agent default frequency before pricing real risk.
  2. External audit of the claim gate and pool share accounting. 94 tests, invariant runs and a clean Slither report are a floor, not a substitute — and a hard prerequisite to mainnet.
  3. Capped mainnet pilot post-audit: hard pool ceiling, existing caps, prove the loss ratio over a real quarter before lifting anything.
  4. FBTC / FDOGE coverage — the RPN machinery is asset-agnostic and generalizes to every FAsset.
  5. Risk-tranched pools (senior / junior) once underwriting demand justifies splitting the curve.

📄 License

MIT © 2026

About

🛟 Backstop — FXRP redemption-default insurance on Flare, triggered by the protocol's own FDC ReferencedPaymentNonexistence proof (Coston2).

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Releases

Used by

Contributors

Languages