Inertia Protocol

Live site & full docs →

A Solana Anchor program that rescues stalled transactions: when a swap fails to land within 2 slots (~800ms), a public keeper gate opens and independent keeper bots race to get it included via Jito private bundles, earning a bounty from a dynamic gas buffer the user posted at submission time. If no keeper acts within 150 slots, the user reclaims the full buffer via self_rescue.

Status: early development, live on Solana devnet, unaudited, not yet on mainnet. A continuous keeper has been running unattended against real liquidity -- see the proof below. Full, current risk list: docs/RISK_REGISTER.md.

Live proof

Quick start

# SDK -- build swaps against a real DEX, or wrap all five instructions
cd packages/sdk && npm install && npm run build

# Reference keeper -- watches devnet, only acts once genuinely profitable.
# The env vars below are real and point at devnet by default -- npm start
# alone connects to a local validator that doesn't exist for you yet.
cd packages/keeper && npm install && npm run build
export INERTIA_KEEPER_RPC_URL="https://api.devnet.solana.com"
export INERTIA_KEEPER_KEYPAIR="/path/to/keypair.json"   # solana-keygen new, funded via devnet faucet
export INERTIA_KEEPER_ORCA_WHIRLPOOL="122n8Kvj9htD1AkY8JWJBMngzA8rWkWDPa26vPpuiU7z" # the real, live pool this repo's own proofs use
npm start

This alone will sit quietly until some escrow targeting that pool actually stalls -- which won't happen on its own. See docs/RUNNING_A_KEEPER.md for the real, step-by-step walkthrough, including how to generate real work for your keeper to find and rescue.

See packages/sdk/README.md and packages/keeper/README.md for real usage examples, or CONTRIBUTING.md to build and fuzz the on-chain program itself.

How it works

flowchart TD
    A["initialize_escrow<br/>user deposits gas buffer, delegates input_amount,<br/>escrow PDA created, status: Pending"] --> B{"Escrow is Pending<br/>anyone may act, behavior branches on elapsed slots"}

    B -->|"elapsed &le; TTL_SLOTS (2 slots, ~800ms)<br/>execute_swap, ordinary attempt"| C["CPI swap via delegated authority"]
    B -->|"elapsed &gt; TTL_SLOTS<br/>execute_swap, rescue attempt<br/>requires a Jito tip, amount decays<br/>from the reward itself down to a floor"| D["CPI swap via delegated authority"]

    C --> E{"output &ge; expected_output_amount?"}
    D --> E
    E -->|"no"| F["reverts, escrow still Pending"]
    E -->|"yes, ordinary path"| G["100% of buffer refunded to user<br/>status: Executed, escrow closed"]
    E -->|"yes, rescue path"| H["buffer split 90 / 5 / 5<br/>caller (keeper) / partner / treasury<br/>status: Executed, escrow closed"]

    B -->|"elapsed &gt; SELF_RESCUE_SLOTS (150 slots)<br/>self_rescue, user_wallet only"| I["token delegation revoked<br/>full buffer + rent returned to user<br/>status: Rescued, escrow closed"]

    B -->|"elapsed &gt; CLEANUP_SLOTS (300 slots)<br/>cleanup_expired_escrow, anyone"| J["10% buffer bounty to caller<br/>90% buffer + rent to user<br/>status: Expired, escrow closed"]

Every threshold is a slot count, not a millisecond value, checked against Clock::get()?.slot -- correct regardless of Solana's actual slot time. execute_swap is the only instruction that performs the underlying swap; self_rescue and cleanup_expired_escrow are pure fallbacks that never touch the swap program. The rescue-path tip is anti-snipe by design: it starts equal to the keeper's own reward right when the TTL elapses, making pure profit-seeking sniping break-even-or-negative at the earliest possible slot, then decays back to a normal floor. Full reasoning and the known residual risk: docs/RISK_REGISTER.md.

Full documentation

Layout

  • programs/inertia-protocol/: the on-chain program
  • packages/sdk/: TypeScript client SDK, including three real, reusable DEX swap-builder clients (Orca, Raydium CPMM, Meteora DLMM) any integrating platform can use directly
  • packages/keeper/: reference open-source keeper bot, consuming those same SDK exports rather than special-casing them
  • trident-tests/: Trident fuzz tests for all three fund-moving instructions -- 100k-iteration campaign, ~663,600 total instruction invocations, zero assertion panics
  • site/: public-facing landing page and /docs (Next.js)

See CONTRIBUTING.md for how to actually build, test, and fuzz this locally.