diff --git a/content/api-reference/pricing-resources/pricing/compute-unit-costs.mdx b/content/api-reference/pricing-resources/pricing/compute-unit-costs.mdx index c026d3868..8272854a2 100644 --- a/content/api-reference/pricing-resources/pricing/compute-unit-costs.mdx +++ b/content/api-reference/pricing-resources/pricing/compute-unit-costs.mdx @@ -220,6 +220,19 @@ The [Solana Account Archive](/docs/solana/account-archive) is served through the | getValidityProofV2 | 1200 | 500 | {/* cu:auto end */} +# Solana: Jito Bundles and Transactions + +[Jito bundles](/docs/chains/solana/solana-jito-bundles-and-transactions) are groups of up to 5 signed transactions that execute sequentially and atomically in a single slot on Solana Mainnet. A tip to one of the Jito tip accounts is required for inclusion. These methods are available on paid Alchemy plans only. + +{/* cu:auto product="solana-jito" */} +| Method | CU | Throughput CU | +| -------------------------- | --- | ------------- | +| getBundleStatuses | 40 | | +| getInflightBundleStatuses | 40 | | +| getTipAccounts | 40 | | +| sendBundle | 40 | | +{/* cu:auto end */} + # Solana: Yellowstone gRPC [Yellowstone gRPC](/docs/reference/yellowstone-grpc-overview) is a high-performance streaming service for Solana that delivers real-time blockchain data via gRPC. Pricing is based on **bandwidth:** the amount of data delivered as part of the stream. diff --git a/content/api-reference/solana/solana-jito-bundles-overview.mdx b/content/api-reference/solana/solana-jito-bundles-overview.mdx new file mode 100644 index 000000000..edf9047b2 --- /dev/null +++ b/content/api-reference/solana/solana-jito-bundles-overview.mdx @@ -0,0 +1,51 @@ +--- +title: Solana Jito Bundles and Transactions +description: Alchemy's Jito bundle APIs for low-latency, atomic transaction execution on Solana. +subtitle: Alchemy's Jito bundle APIs for low-latency, atomic transaction execution on Solana. +--- + + + Jito bundle methods are available on **paid plans only** (pay-as-you-go and enterprise). Free-tier accounts cannot call these endpoints. [Upgrade your account](https://dashboard.alchemy.com/settings/billing) to enable Jito bundles. + + +## Background + +A **bundle** is a group of up to 5 signed Solana transactions that execute: + +* **Sequentially** — in the exact order you list them. +* **Atomically** — within a single slot, all-or-nothing. If any transaction fails, none of them commit to the chain. + +Bundles are the standard MEV primitive on Solana today: multi-leg arbitrage, backrunning, atomic setup-and-cleanup, and launch sniping with revert guards all rely on the atomicity a bundle provides. + +## How the auction works + +Bundles do not go through Solana's normal gossip path. They go to the [Jito Block Engine](https://docs.jito.wtf/lowlatencytxnsend/#how-does-the-system-work), which collects bundles from searchers, simulates them, runs a sealed-bid auction per block, and forwards winners to the current leader when that leader runs `Jito-Solana` (about 95% of Solana stake at time of writing). + +Your bid in that auction is the **Jito tip** — a plain SOL transfer to one of the [8 tip accounts](/docs/chains/solana/solana-jito-bundles-and-transactions/solana-jito-bundles-and-transactions/get-tip-accounts) returned by `getTipAccounts`, included in one of your bundle's transactions. The minimum tip is 1,000 lamports; contested MEV opportunities can require substantially higher tips. See Jito's [tip amount guidance](https://docs.jito.wtf/lowlatencytxnsend/#tip-amount) for current recommendations. + +## Endpoint + +Jito bundle methods are available on **Solana Mainnet only** through the standard Alchemy Solana RPC endpoint: + +```text +https://solana-mainnet.g.alchemy.com/v2/{apiKey} +``` + +Devnet is not supported. These endpoints require a paid Alchemy plan (pay-as-you-go or enterprise); they are not available on the free tier. + +## Methods + +| Method | Function | CU cost | +| --- | --- | --- | +| [sendBundle](/docs/chains/solana/solana-jito-bundles-and-transactions/solana-jito-bundles-and-transactions/send-bundle) | Submit a bundle of up to 5 signed transactions to the block engine for atomic execution. | 40 | +| [getBundleStatuses](/docs/chains/solana/solana-jito-bundles-and-transactions/solana-jito-bundles-and-transactions/get-bundle-statuses) | Return the on-chain landing status of one or more submitted bundle IDs. | 40 | +| [getTipAccounts](/docs/chains/solana/solana-jito-bundles-and-transactions/solana-jito-bundles-and-transactions/get-tip-accounts) | Retrieve the 8 Jito tip accounts designated to receive bundle tips. | 40 | +| [getInflightBundleStatuses](/docs/chains/solana/solana-jito-bundles-and-transactions/solana-jito-bundles-and-transactions/get-inflight-bundle-statuses) | Query the in-flight status (`Pending`, `Landed`, `Failed`, `Invalid`) of bundles submitted in the last 5 minutes. | 40 | + +For deeper background on bundle mechanics, tip strategy, sandwich mitigation via `jitodontfront`, and Jito's own SDKs (Python, JS/TS, Rust, Go), see Jito's [Low Latency Transaction Send docs](https://docs.jito.wtf/lowlatencytxnsend/#bundles-api-v1). + +## Related + +* [`simulateBundle`](/docs/chains/solana/solana-api-endpoints/simulate-bundle) — simulate a Jito bundle before submitting it, without paying a tip. +* [`sendTransaction`](/docs/chains/solana/solana-api-endpoints/send-transaction) — standard Solana single-transaction submission. +* [MEV Protection](/docs/reference/mev-protection) — Alchemy's built-in MEV protection for standard Solana transactions. diff --git a/content/docs.yml b/content/docs.yml index f6c9f0319..63aa3b3e2 100644 --- a/content/docs.yml +++ b/content/docs.yml @@ -346,6 +346,13 @@ navigation: - api: Solana Photon API api-name: solana-photon flattened: true + - section: Solana Jito Bundles and Transactions + path: >- + api-reference/solana/solana-jito-bundles-overview.mdx + contents: + - api: Solana Jito Bundles and Transactions + api-name: solana-jito + flattened: true - section: Tutorials contents: - link: Hello World Solana Application diff --git a/src/openrpc/alchemy/solana-jito/solana-jito.yaml b/src/openrpc/alchemy/solana-jito/solana-jito.yaml new file mode 100644 index 000000000..243a20ee1 --- /dev/null +++ b/src/openrpc/alchemy/solana-jito/solana-jito.yaml @@ -0,0 +1,32 @@ +# yaml-language-server: $schema=https://meta.open-rpc.org/ + +$schema: https://meta.open-rpc.org/ +openrpc: 1.2.4 +info: + title: Alchemy Solana Jito Bundles and Transactions Specification + description: |- + JSON-RPC specification for the [Jito](https://docs.jito.wtf/lowlatencytxnsend/#bundles-api-v1) + low-latency bundle methods on Solana. Bundles are groups of up to 5 + transactions that execute sequentially and atomically in a single slot, with + a tip to one of the Jito tip accounts to incentivize inclusion. Available on + Solana Mainnet only. + version: 0.0.0 +servers: + - url: https://solana-mainnet.g.alchemy.com/v2 + name: Solana Mainnet +x-auth-params: + - name: apiKey + in: path + required: true + schema: + type: string + default: YOUR_API_KEY + description: >- + Jito bundle methods are available on paid Alchemy plans only. [Create + an API key](https://dashboard.alchemy.com/signup) on a paid plan (pay-as-you-go + or enterprise) to call these endpoints. +methods: + - $ref: ../../chains/_components/solana/methods.yaml#/components/methods/sendBundle + - $ref: ../../chains/_components/solana/methods.yaml#/components/methods/getBundleStatuses + - $ref: ../../chains/_components/solana/methods.yaml#/components/methods/getTipAccounts + - $ref: ../../chains/_components/solana/methods.yaml#/components/methods/getInflightBundleStatuses diff --git a/src/openrpc/chains/_components/solana/methods.yaml b/src/openrpc/chains/_components/solana/methods.yaml index 07ba1ae47..59ae6c998 100644 --- a/src/openrpc/chains/_components/solana/methods.yaml +++ b/src/openrpc/chains/_components/solana/methods.yaml @@ -1082,6 +1082,246 @@ components: schema: $ref: "./transaction.yaml#/components/schemas/SimulatedBundleResult" + sendBundle: + name: sendBundle + summary: Submit a Jito bundle to the block engine. + description: >- + Available on paid Alchemy plans (pay-as-you-go or enterprise); not available on the free tier. + + + Submits a bundle of signed transactions to the Jito block engine for atomic + processing. Transactions are processed sequentially in the order given; if any + transaction fails, the entire bundle is rejected (all-or-nothing). Returns a + `bundle_id` immediately once the bundle is accepted; this does not guarantee + the bundle lands on-chain. Use [`getBundleStatuses`](/docs/chains/solana/solana-jito-bundles-and-transactions/solana-jito-bundles-and-transactions/get-bundle-statuses) + or [`getInflightBundleStatuses`](/docs/chains/solana/solana-jito-bundles-and-transactions/solana-jito-bundles-and-transactions/get-inflight-bundle-statuses) + to poll the bundle's status. + + + A tip is required for the bundle to be considered. The tip can be any + instruction (top-level or CPI) that transfers SOL to one of the 8 Jito tip + accounts. Use [`getTipAccounts`](/docs/chains/solana/solana-jito-bundles-and-transactions/solana-jito-bundles-and-transactions/get-tip-accounts) + to retrieve them, and randomize the selection to reduce contention. The + minimum tip is 1,000 lamports; competitive MEV opportunities may require + significantly higher tips. + + + See Jito's [Low Latency Transaction Send](https://docs.jito.wtf/lowlatencytxnsend/#sendbundle) + docs for background on bundle mechanics. + x-compute-units: 40 + params: + - name: Encoded transactions + required: true + description: >- + Fully-signed transactions as base64 (recommended) or base58 (deprecated) + encoded strings. Maximum of 5 transactions. + schema: + type: array + maxItems: 5 + items: + type: string + - name: Configuration + required: false + description: Optional configuration object specifying the encoding used for the transactions. + schema: + $ref: "./transaction.yaml#/components/schemas/SendBundleConfig" + examples: + - name: sendBundle example + params: + - name: Encoded transactions + value: + - "AT2AqtlokikUWgGNnSX5xrmdvBjSaiIPxvFz6zc5Abn5Z0CPFW5GO+Y3rXceLnqLgQFnGw0yTk3NtJdFNsbrwwQBAAIEsXPDJ9cMVbpFQYClVM7PGLh8JOfCD6E2vz5VNmBCF+p4Uhyxec67hYm1VqLV7JTSSYaC/fm7KvWtZOSRzEFT2gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABUpTWpkpIQZNJOhxYNo4fHw1td28kruB5B+oQEEFRI1i3Wzl2VfewCI8oYXParnP78725sKFzYheTEn8v865YQIDABhqaXRvIGJ1bmRsZSAwOiBqaXRvIHRlc3QCAgABDAIAAACghgEAAAAAAA==" + - "AS6fOZuGDsmyYdd+RC0fiFUgNe1BYTOYT+1hkRXHAeroC8R60h3g34EPF5Ys8sGzVBMP9MDSTVgy1/SSTqpCtA4BAAIEsXPDJ9cMVbpFQYClVM7PGLh8JOfCD6E2vz5VNmBCF+p4Uhyxec67hYm1VqLV7JTSSYaC/fm7KvWtZOSRzEFT2gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABUpTWpkpIQZNJOhxYNo4fHw1td28kruB5B+oQEEFRI1i3Wzl2VfewCI8oYXParnP78725sKFzYheTEn8v865YQIDABhqaXRvIGJ1bmRsZSAxOiBqaXRvIHRlc3QCAgABDAIAAACghgEAAAAAAA==" + - name: Configuration + value: + encoding: base64 + result: + name: Bundle ID + value: "2id3YC2jK9G5Wo2phDx4gJVAew8DcY5NAojnVuao8rkxwPYPe8cSwE5GzhEgJA2y8fVjDEo6iR6ykBvDxrTQrtpb" + result: + name: Bundle ID + description: The bundle ID, used to identify the bundle. This is the SHA-256 hash of the bundle's transaction signatures. + schema: + type: string + + getBundleStatuses: + name: getBundleStatuses + summary: Get the status of submitted Jito bundles. + description: >- + Available on paid Alchemy plans (pay-as-you-go or enterprise); not available on the free tier. + + + Returns the status of submitted bundle(s). This function operates similarly + to the Solana RPC method `getSignatureStatuses`. If a `bundle_id` is not + found or has not landed, it returns `null`. If found and processed, it + returns context information including the slot at which the request was + made and results with the `bundle_id(s)` and the transactions along with + their slot and confirmation status. + + + We use `getSignatureStatuses` with the default value of + `searchTransactionHistory` set to `false` to check transaction statuses + on-chain. This means the RPC call will search only its recent history, + including all recent slots plus up to `MAX_RECENT_BLOCKHASHES` rooted slots + for the transactions. Currently, `MAX_RECENT_BLOCKHASHES` is 300. + + + See Jito's [getBundleStatuses](https://docs.jito.wtf/lowlatencytxnsend/#getbundlestatuses) + docs for background. + x-compute-units: 40 + params: + - name: Bundle IDs + required: true + description: An array of bundle IDs to confirm. Maximum of 5. + schema: + type: array + maxItems: 5 + items: + type: string + examples: + - name: getBundleStatuses example + params: + - name: Bundle IDs + value: + - "892b79ed49138bfb3aa5441f0df6e06ef34f9ee8f3976c15b323605bae0cf51d" + result: + name: Bundle statuses + value: + context: + slot: 242806119 + value: + - bundle_id: "892b79ed49138bfb3aa5441f0df6e06ef34f9ee8f3976c15b323605bae0cf51d" + transactions: + - "3bC2M9fiACSjkTXZDgeNAuQ4ScTsdKGwR42ytFdhUvikqTmBheUxfsR1fDVsM5ADCMMspuwGkdm1uKbU246x5aE3" + - "8t9hKYEYNbLvNqiSzP96S13XF1C2f1ro271Kdf7bkZ6EpjPLuDff1ywRy4gfaGSTubsM2FeYGDoT64ZwPm1cQUt" + slot: 242804011 + confirmation_status: "finalized" + err: + Ok: null + result: + name: Bundle statuses + description: The status of each submitted bundle, or an empty `value` array if none of the requested bundles are found in recent slots. + schema: + $ref: "./transaction.yaml#/components/schemas/BundleStatusesResult" + + getTipAccounts: + name: getTipAccounts + summary: Get the Jito tip accounts. + description: >- + Available on paid Alchemy plans (pay-as-you-go or enterprise); not available on the free tier. + + + Retrieves the tip accounts designated for tip payments for bundles. The + tip accounts have remained constant and can also be found in the + [example response](https://docs.jito.wtf/lowlatencytxnsend/#response-example-tips) + of Jito's docs. + + + See Jito's [getTipAccounts](https://docs.jito.wtf/lowlatencytxnsend/#gettipaccounts) + docs for background. + x-compute-units: 40 + params: + - name: Placeholder + required: false + description: >- + Not read by the server. Included so the JSON-RPC `params` field is + present in the request body. Leave the pre-filled empty object as-is. + schema: + type: object + default: {} + examples: + - name: getTipAccounts example + params: + - name: Placeholder + value: {} + result: + name: Tip accounts + value: + - "96gYZGLnJYVFmbjzopPSU6QiEV5fGqZNyN9nmNhvrZU5" + - "HFqU5x63VTqvQss8hp11i4wVV8bD44PvwucfZ2bU7gRe" + - "Cw8CFyM9FkoMi7K7Crf6HNQqf4uEMzpKw6QNghXLvLkY" + - "ADaUMid9yfUytqMBgopwjb2DTLSokTSzL1zt6iGPaS49" + - "DfXygSm4jCyNCybVYYK6DwvWqjKee8pbDmJGcLWNDXjh" + - "ADuUkR4vqLUMWXxW9gh6D6L8pMSawimctcNZ5pGwDcEt" + - "DttWaMuVvTiduZRnguLF7jNxTgiMBZ1hyAumKUiL2KRL" + - "3AVi9Tg9Uo68tJfuvoKvqKNWKkC5wPdSSdeBnizKZ6jT" + result: + name: Tip accounts + description: The list of 8 Jito tip accounts as base-58 encoded pubkey strings. + schema: + type: array + items: + $ref: "./base-types.yaml#/components/schemas/Pubkey" + + getInflightBundleStatuses: + name: getInflightBundleStatuses + summary: Get the in-flight status of Jito bundles from the last 5 minutes. + description: >- + Available on paid Alchemy plans (pay-as-you-go or enterprise); not available on the free tier. + + + Returns the status of submitted bundles within the last five minutes, + allowing up to five bundle IDs per request. + + + * **Failed**: Indicates that all regions have marked the bundle as failed, and it has not been forwarded. + + * **Pending**: Indicates the bundle has not failed, landed, or been deemed invalid. + + * **Landed**: Signifies the bundle has successfully landed on-chain, verified through RPC or the `bundles_landed` table. + + * **Invalid**: Means the bundle is no longer in the system. + + + See Jito's [getInflightBundleStatuses](https://docs.jito.wtf/lowlatencytxnsend/#getinflightbundlestatuses) + docs for background. + x-compute-units: 40 + params: + - name: Bundle IDs + required: true + description: An array of bundle IDs to confirm. Maximum of 5. + schema: + type: array + maxItems: 5 + items: + type: string + examples: + - name: getInflightBundleStatuses example + params: + - name: Bundle IDs + value: + - "b31e5fae4923f345218403ac1ab242b46a72d4f2a38d131f474255ae88f1ec9a" + - "e3c4d7933cf3210489b17307a14afbab2e4ae3c67c9e7157156f191f047aa6e8" + - "a7abecabd9a165bc73fd92c809da4dc25474e1227e61339f02b35ce91c9965e2" + - "e3934d2f81edbc161c2b8bb352523cc5f74d49e8d4db81b222c553de60a66514" + - "2cd515429ae99487dfac24b170248f6929e4fd849aa7957cccc1daf75f666b54" + result: + name: Inflight bundle statuses + value: + context: + slot: 280999028 + value: + - bundle_id: "b31e5fae4923f345218403ac1ab242b46a72d4f2a38d131f474255ae88f1ec9a" + status: "Invalid" + landed_slot: null + - bundle_id: "e3c4d7933cf3210489b17307a14afbab2e4ae3c67c9e7157156f191f047aa6e8" + status: "Invalid" + landed_slot: null + - bundle_id: "a7abecabd9a165bc73fd92c809da4dc25474e1227e61339f02b35ce91c9965e2" + status: "Invalid" + landed_slot: null + - bundle_id: "e3934d2f81edbc161c2b8bb352523cc5f74d49e8d4db81b222c553de60a66514" + status: "Invalid" + landed_slot: null + - bundle_id: "2cd515429ae99487dfac24b170248f6929e4fd849aa7957cccc1daf75f666b54" + status: "Invalid" + landed_slot: null + result: + name: Inflight bundle statuses + description: The in-flight status of each queried bundle. + schema: + $ref: "./transaction.yaml#/components/schemas/InflightBundleStatusesResult" + getSignaturesForAddress: name: getSignaturesForAddress description: Returns signatures for confirmed transactions that include the given address. diff --git a/src/openrpc/chains/_components/solana/transaction.yaml b/src/openrpc/chains/_components/solana/transaction.yaml index 188f2c975..abc7c553e 100644 --- a/src/openrpc/chains/_components/solana/transaction.yaml +++ b/src/openrpc/chains/_components/solana/transaction.yaml @@ -542,3 +542,102 @@ components: $ref: "./base-types.yaml#/components/schemas/Commitment" minContextSlot: $ref: "./base-types.yaml#/components/schemas/MinContextSlot" + SendBundleConfig: + title: SendBundle Configuration + type: object + properties: + encoding: + type: string + description: Encoding used for the transaction data. `base64` is recommended; `base58` is deprecated. + enum: + - base64 + - base58 + default: base58 + BundleStatus: + title: Bundle Status + type: object + properties: + bundle_id: + type: string + description: The bundle ID. + transactions: + type: array + items: + type: string + description: The list of base-58 encoded transaction signatures in the bundle. The list will not be empty. + slot: + type: integer + description: The slot in which this bundle was processed. + confirmation_status: + type: string + description: The bundle transactions' cluster confirmation status; either `processed`, `confirmed`, or `finalized`. + enum: + - processed + - confirmed + - finalized + err: + type: object + nullable: true + description: The retryable or non-retryable error encountered when getting the bundle status. If retryable, query again. + BundleStatusesResult: + title: Bundle Statuses Result + type: object + nullable: true + description: An RPC response containing the bundle statuses, or `null` if none of the requested bundles are found. + properties: + context: + type: object + properties: + slot: + type: integer + description: The slot at which the request was processed. + value: + type: array + description: An array of bundle status objects. Empty if none of the requested bundles are found. + items: + $ref: "#/components/schemas/BundleStatus" + InflightBundleStatus: + title: Inflight Bundle Status + type: object + properties: + bundle_id: + type: string + description: The bundle ID. + status: + type: string + description: >- + The inflight status of the bundle. + + `Invalid`: bundle ID is not in the block engine's 5-minute look back window. + + `Pending`: bundle has not failed, landed, or been marked invalid. + + `Failed`: every region that received the bundle has marked it as failed and it has not been forwarded. + + `Landed`: bundle has landed on-chain, verified via RPC or the `bundles_landed` table. + enum: + - Invalid + - Pending + - Failed + - Landed + landed_slot: + type: integer + nullable: true + description: The slot the bundle landed in, or `null` if the bundle is `Invalid`, `Pending`, or `Failed`. + InflightBundleStatusesResult: + title: Inflight Bundle Statuses Result + type: object + nullable: true + description: An RPC response containing the inflight bundle statuses, or `null` if none of the requested bundles are found. + properties: + context: + type: object + properties: + slot: + type: integer + description: The slot at which the request was processed. + value: + type: array + description: An array of inflight bundle status objects. + items: + $ref: "#/components/schemas/InflightBundleStatus" diff --git a/src/utils/generateRpcSpecs.ts b/src/utils/generateRpcSpecs.ts index ff92b37d8..6ab0f2711 100644 --- a/src/utils/generateRpcSpecs.ts +++ b/src/utils/generateRpcSpecs.ts @@ -27,10 +27,14 @@ const generateOpenRpcSpecFromSource = async ( })) as DerefedOpenRpcDoc & { [SERVER_URL_FINAL_KEY]?: boolean }; const skipApiKeyParam = spec[SERVER_URL_FINAL_KEY] === true; + const hasCustomAuthParams = + Array.isArray((spec as Record)["x-auth-params"]) && + ((spec as Record)["x-auth-params"] as unknown[]).length > + 0; const { [SERVER_URL_FINAL_KEY]: _skipKey, ...specWithoutKey } = spec; const fullSpec = { ...specWithoutKey, - ...(skipApiKeyParam + ...(skipApiKeyParam || hasCustomAuthParams ? {} : { "x-auth-params": [