Skip to content

About

No description, website, or topics provided.

Resources

Stars

1 star

Watchers

0 watching

Forks

Latest commit

 

History

12 Commits

Folders and files

Repository files navigation

Smart Transaction Stack (Solana · Jito · Yellowstone · AI agent)

A production-shaped Solana transaction stack that:

  • streams live slot + leader data over Yellowstone gRPC (with reconnect + backpressure handling),
  • constructs and submits Jito bundles with dynamically computed tips from live tip-floor telemetry (no hardcoded tip values),
  • tracks the full submitted → processed → confirmed → finalized lifecycle, confirming landing from the stream (RPC is only a cross-check),
  • classifies failures (expired blockhash, fee too low, compute exceeded, bundle failure, leader skip), and
  • hands one real operational decision to an AI agent: it reasons about why a submission failed and autonomously plans the retry (refresh blockhash, recompute tip, wait for a Jito leader). It also owns tip pricing and submit timing.

Layout

src/
  config.ts              env loading + operational constants
  types.ts               domain types (stages, failure classes, records)
  logger.ts              JSONL lifecycle log + latency-delta computation
  monitor/slotMonitor.ts Yellowstone gRPC: slots, leaders, sig observations
  jito/tipFloor.ts       live tip accounts + tip-floor percentiles
  jito/bundleClient.ts   sendBundle / getBundleStatuses / inflight
  tx/builder.ts          versioned tx + tip ix; fresh & (injected) expired blockhash
  tx/failures.ts         failure classifier
  tx/lifecycle.ts        stream-first commitment tracking
  agent/agent.ts         AI layer (tip, timing, failure reasoning + retry)
  orchestrator.ts        ties it together; agent-driven retry loop
  index.ts               entrypoint; runs N submissions, writes the log

The AI layer (agent/) is deliberately isolated from the core stack: it receives a structured snapshot and returns a structured decision + reasoning. No retry/tip policy is hardcoded in the stack — it all flows through the agent, with a post-hoc tip ceiling as a pure safety clamp.

Setup

  1. npm install
  2. Create a funded mainnet keypair: solana-keygen new -o wallet.json and send it a little SOL (~0.02 covers a full run of tips + fees).
  3. cp .env.example .env and fill in: RPC, Yellowstone endpoint + token, ANTHROPIC_API_KEY, wallet path. (Bounty infra credits from SolInfra cover the RPC + Yellowstone endpoints.)
  4. Dry-run the wiring without spending anything: npm run run:demo
  5. Real run (produces the verifiable log): npm start

Output: ./logs/lifecycle.jsonl — one JSON object per submission with slot numbers, signature, bundle id, tip, stage timestamps, latency deltas, failure class, and the agent's recorded decisions. FAULT_INJECT_INDEX forces one expired-blockhash failure so the agent's autonomous recovery is captured in the log.


Required README answers

Q1 — What does the delta between processed_at and confirmed_at tell you about network health?

processed means the block containing your transaction exists (one node built it); it may still be on a minor fork. confirmed means a supermajority (≈⅔ of stake) has voted on that block. So the processed→confirmed delta is essentially a vote-propagation / consensus-latency measurement at that moment: how long it took the cluster to reach supermajority agreement on the slot your tx landed in.

A small, stable delta (e.g. ~400ms in our runs, occasionally dipping to 10ms or going negative when the stream confirmed before RPC caught up) means validators are voting promptly. In our runs, periods of null deltas correlated directly with bundle auction losses — the agent correctly interpreted these as congestion signals and chose to hold.

Q2 — Why should you never use finalized commitment when fetching a blockhash for a time-sensitive transaction?

A blockhash is only valid for ~150 slots (~60–90s) after the block it references. finalized lags the chain tip by ~32 slots (~12–15s), so a blockhash fetched at finalized is already ~32 slots old the instant you receive it — you've burned ~20%+ of its validity window before signing, leaving a much shorter effective lifetime and a much higher chance of "blockhash not found"/expiry before the bundle lands. For a Jito bundle that must reach a leader within a tight window (and may be retried), you want maximum runway, so fetch at confirmed (or processed) to get the freshest blockhash with the full ~150-slot window. The stack fetches at confirmed in getFreshBlockhash.

Q3 — What happens to your bundle if the Jito leader skips their slot?

Bundles are only executed while a Jito-Solana leader is the active leader; the block engine forwards your bundle to the upcoming Jito leader. If that leader skips their slot (produces no block), your bundle is simply not included — it does not land. It is not automatically carried to the next leader by that submission, and because bundles are all-or-nothing, no transactions land and no tip is paid (the tip only settles if the bundle lands). Meanwhile your blockhash keeps counting down toward expiry. Net effect: a silent miss that you must detect and resubmit — ideally targeting the next Jito leader window, and refreshing the blockhash if enough slots have passed. The stack classifies this as leader_skipped (target slot never reaches any commitment status while a later slot has), and the agent's retry plan waits for the next Jito window rather than just bumping the tip.


Notes / honesty about limits

  • "Jito leader" detection here uses the upcoming-leader schedule plus the block engine's own acceptance signal. ~95% of stake runs jito-solana, so most windows qualify; for a stricter check, cross-reference upcoming leaders against Jito's published validator set.

  • The demo payload is a 0-lamport self-transfer plus the tip, so the bundle is real and verifiable on-chain without doing anything economically meaningful. Swap in your own instructions as needed. HEAD

  • Yellowstone slot-status enum mapping varies slightly by provider/version; normalizeSlotStatus handles both string and numeric forms — verify against your endpoint.

  • Yellowstone slot-status enum mapping varies slightly by provider/version; normalizeSlotStatus handles both string and numeric forms — verify against your endpoint. 4977dab (add real observations to README Q1)

About

No description, website, or topics provided.

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages