# Transaction Submission -- MEV, Protected Paths, and Landing Optimization on Solana **Applies to:** All Solana protocols that submit transactions programmatically (bots, relayers, cranks, frontends, aggregators) **Audience:** Protocol developers, bot operators, security engineers, frontend developers, MEV researchers **Related:** [[rpc-security]], [[hot-wallets]], [[monitoring]], [[circuit-breakers]] --- ## 1. Transaction Submission Paths on Solana When a Solana transaction is created and signed, it must be delivered to a leader validator for inclusion in a block. How the transaction reaches the leader -- the submission path -- has significant security and performance implications. ### 1.1 The Default Path: Public RPC The simplest submission path is through a public RPC endpoint: ``` User/Bot -> RPC Provider -> QUIC connection to leader -> Block inclusion ``` When you call `sendTransaction` on an RPC provider (e.g., Helius, QuickNode, Triton, the public Solana RPC), the provider forwards your transaction to the current leader validator's TPU (Transaction Processing Unit) port via QUIC. **What happens in this path:** 1. Your signed transaction is sent to the RPC provider 2. The RPC provider adds the transaction to its forwarding queue 3. The RPC provider forwards the transaction to the current and upcoming leader validators 4. The leader validator includes the transaction in a block (if it passes validation and there is space) **Security considerations of the default path:** | Consideration | Detail | |---------------|--------| | **Visibility** | Your transaction is visible to the RPC provider. The provider can see the contents, the accounts involved, and the amounts. | | **No ordering guarantees** | The RPC provider does not guarantee any particular ordering of your transaction relative to others. | | **Vulnerable to searcher activity** | Searchers monitoring the transaction pipeline can observe your transaction and react to it (see Section 2). | | **Landing rate depends on fees** | During congestion, transactions with insufficient priority fees may not land at all. | ### 1.2 Direct TPU Submission Applications can bypass the RPC provider and submit directly to the leader validator's TPU port via QUIC: ``` User/Bot -> QUIC connection to leader -> Block inclusion ``` This requires: - Knowing the current and upcoming leader validators (from the leader schedule) - Establishing a QUIC connection to the leader's TPU port - Managing connection pooling, retries, and failover **Advantages:** - Lower latency (no RPC provider hop) - No RPC provider seeing your transaction - More control over retry logic and timing **Disadvantages:** - Significant engineering complexity - Must track the leader schedule and maintain connections to multiple validators - Must handle QUIC connection management, including rate limiting and connection reuse - Still visible to the leader validator and any searchers with validator-level access ### 1.3 Jito Bundles Jito provides a block engine that allows users to submit transaction bundles with tips: ``` User/Bot -> Jito Block Engine -> Jito-Solana validator -> Block inclusion ``` A bundle is an ordered set of transactions that must execute atomically -- either all transactions in the bundle execute in the specified order, or none of them execute. **Jito bundle properties:** | Property | Detail | |----------|--------| | **Atomic execution** | All transactions in the bundle execute in order, or none execute. No partial execution. | | **Tip-based priority** | Bundles include a tip (in SOL) that incentivizes validators to include the bundle. Higher tips = higher priority. | | **Revert protection** | If any transaction in the bundle would fail, the entire bundle is dropped. The tip is not paid for failed bundles. | | **Front-running protection** | Transactions within a bundle cannot be reordered or interspersed with other transactions by the validator. The bundle is an atomic unit. | ### 1.4 Private Submission Channels Some RPC providers and MEV protection services offer private transaction submission channels: | Provider | Feature | How It Works | |----------|---------|-------------| | **Jito** | Bundle submission via Block Engine API | Transactions submitted as bundles with atomic execution guarantees | | **Helius** | Priority fee optimization and staked connections | Uses staked validator connections for improved landing rates | | **Triton** | Staked connections | Direct connections to validators for improved delivery | | **bloXroute** | Protected submission | Private mempool-like service for transaction privacy | --- ## 2. MEV on Solana ### 2.1 What Is MEV? MEV (Maximal Extractable Value) is the profit that can be extracted by controlling transaction ordering within a block. On Solana, MEV primarily manifests as: - **Arbitrage:** Exploiting price differences between markets by inserting transactions that capture the spread. - **Sandwich attacks:** Detecting a user's pending swap, placing a trade before it (front-run) and after it (back-run) to extract value from the price impact. - **Liquidation racing:** Competing to be the first to liquidate an undercollateralized position, earning the liquidation reward. - **Just-In-Time (JIT) liquidity:** Adding liquidity to a pool just before a large trade (to earn fees) and removing it immediately after. ### 2.2 How Searchers Operate on Solana Searchers on Solana monitor for profitable opportunities through several channels: | Channel | How Searchers See Transactions | |---------|-------------------------------| | **RPC provider partnerships** | Some searchers have arrangements with RPC providers to observe pending transactions | | **Validator access** | Searchers running their own validators can see transactions in the TPU queue | | **On-chain event monitoring** | Searchers monitor on-chain state changes and account updates to detect opportunities | | **Mempool-like observation** | While Solana does not have a traditional mempool, the QUIC transaction pipeline creates observation windows | ### 2.3 Sandwich Attacks A sandwich attack targets a user's swap transaction: 1. **Observation:** Searcher detects a pending swap (e.g., buy 100 SOL worth of Token X on a DEX) 2. **Front-run:** Searcher buys Token X before the user's transaction, pushing the price up 3. **User's transaction:** User's swap executes at the now-higher price, getting fewer tokens 4. **Back-run:** Searcher sells Token X after the user's transaction, capturing the price difference **Impact:** The user receives fewer tokens than they would have without the sandwich. The difference is the searcher's profit. **On Solana, sandwich attacks are possible but harder than on Ethereum because:** - Solana does not have a persistent public mempool - Transaction ordering within a block is determined by the leader validator - Jito bundles can provide atomic execution that prevents interleaving **However, sandwich attacks still occur through:** - Searchers with RPC-level or validator-level visibility - Front-running via faster submission paths - Monitoring on-chain state for predictable transactions ### 2.4 Who Is Affected? | User Type | MEV Risk | Primary Threat | |-----------|----------|----------------| | **DeFi users making swaps** | High | Sandwich attacks extract value from price impact | | **Liquidation bots** | Medium | Racing against other liquidators reduces profits | | **Protocol cranks/keepers** | Medium | Transaction competition and front-running of keeper operations | | **Treasury operations** | High | Large token swaps can be front-run for significant value extraction | | **Multisig signers** | Low-Medium | Multisig operations are generally lower MEV risk, but large treasury swaps are exceptions | --- ## 3. Protected Submission Paths ### 3.1 When to Use Protected Submission Not every transaction needs MEV protection. The cost and complexity of protected submission should be weighed against the potential MEV exposure: | Transaction Type | MEV Exposure | Protection Recommendation | |------------------|-------------|--------------------------| | **Large swaps (>$10K)** | High | Use protected submission (bundles or private channels) | | **Treasury token operations** | High | Use protected submission with slippage protection | | **Liquidation transactions** | Medium | Use bundles for atomicity and priority | | **Keeper/crank operations** | Medium | Consider bundles for time-sensitive operations | | **Small user swaps (<$1K)** | Low | Standard RPC is often sufficient with slippage limits | | **Program upgrades** | None | Standard multisig workflow | | **Admin operations** | None | Standard multisig workflow | | **SOL transfers** | None | Standard RPC | ### 3.2 Using Jito Bundles **When to use:** - Transactions where ordering matters (e.g., arbitrage, liquidation) - Transactions that need revert protection (only pay if the transaction succeeds) - Operations that must be atomic (multiple transactions that must execute together) - Transactions vulnerable to sandwich attacks **How to submit a Jito bundle:** ```typescript import { Connection, Transaction, Keypair } from '@solana/web3.js'; const JITO_BLOCK_ENGINE_URL = 'https://mainnet.block-engine.jito.wtf'; async function submitJitoBundle( transactions: Transaction[], signers: Keypair[], tipLamports: number, ): Promise<string> { // Create tip transaction (pays the validator for bundle inclusion) const tipTransaction = createTipTransaction(tipLamports); transactions.push(tipTransaction); // Sign all transactions // ... signing logic ... // Submit bundle to Jito Block Engine const response = await fetch( `${JITO_BLOCK_ENGINE_URL}/api/v1/bundles`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ jsonrpc: '2.0', id: 1, method: 'sendBundle', params: [serializedTransactions], }), } ); const result = await response.json(); return result.result; // Bundle ID } ``` **Tip sizing:** The tip should be sufficient to incentivize validator inclusion but not excessive. Tips are paid in SOL to one of the Jito tip accounts. Research current tip levels for your transaction type -- they vary based on network conditions and competition. ### 3.3 Revert-Protected Flows Revert protection ensures you do not pay transaction fees for transactions that would fail. This is particularly important for: - **Liquidation bots:** Avoid paying fees when racing against other liquidators and losing - **Arbitrage operations:** Avoid paying fees when the opportunity closes before execution - **Conditional operations:** Operations that should only execute if certain on-chain conditions are met Jito bundles provide revert protection by default -- the tip is only paid if all transactions in the bundle succeed. Without bundles, a failed transaction still costs the base fee. ### 3.4 Slippage Protection Regardless of the submission path, always implement slippage protection for swaps and other price-dependent operations: ```rust /// Execute a swap with slippage protection. /// The transaction fails if the output amount is below the minimum. pub fn swap_with_slippage( ctx: Context<Swap>, amount_in: u64, minimum_amount_out: u64, // Slippage protection ) -> Result<()> { // ... swap logic ... let actual_amount_out = calculate_swap_output(amount_in, pool_state)?; require!( actual_amount_out >= minimum_amount_out, ErrorCode::SlippageExceeded ); // ... transfer logic ... Ok(()) } ``` **Setting slippage limits:** | Context | Suggested Slippage | Rationale | |---------|-------------------|-----------| | Stablecoin swaps | 0.1-0.5% | Stablecoins should trade near peg. Wide slippage indicates a problem. | | Major pair swaps (SOL/USDC) | 0.5-1% | Liquid markets with tight spreads. | | Altcoin swaps | 1-3% | Less liquid markets with wider spreads. | | Treasury operations (large) | 0.3-1% | Large trades move the market. Use protected submission AND tight slippage. | | Automated/bot operations | Set per-strategy | Bots should calculate expected output and set slippage dynamically based on market conditions. | --- ## 4. Priority Fee Considerations ### 4.1 How Priority Fees Work on Solana Solana transactions can include a priority fee (also called a "compute unit price") that incentivizes validators to include the transaction with higher priority. The priority fee is specified in micro-lamports per compute unit. ```typescript import { ComputeBudgetProgram } from '@solana/web3.js'; // Set compute unit price (priority fee) const priorityFeeInstruction = ComputeBudgetProgram.setComputeUnitPrice({ microLamports: 10000, // micro-lamports per compute unit }); // Set compute unit limit const computeLimitInstruction = ComputeBudgetProgram.setComputeUnitLimit({ units: 200000, // requested compute units }); // Add both instructions to your transaction transaction.add(priorityFeeInstruction, computeLimitInstruction); ``` ### 4.2 Priority Fee Strategy | Scenario | Priority Fee Approach | |----------|----------------------| | **Normal conditions** | Use dynamic fee estimation. Query recent block priority fees and set accordingly. | | **Network congestion** | Increase priority fees to ensure landing. Monitor landing rates and adjust. | | **Time-sensitive operations** (liquidations, arbitrage) | Use higher priority fees. The cost of not landing is greater than the fee. | | **Non-urgent operations** (keeper tasks, routine maintenance) | Use lower priority fees. Retry if the transaction does not land. | | **Emergency operations** (circuit breaker activation) | Use very high priority fees. Landing speed is critical. | ### 4.3 Dynamic Fee Estimation Do not hardcode priority fees. Use dynamic estimation based on recent network conditions: ```typescript const RPC_URL = 'https://api.mainnet-beta.solana.com'; async function getRecommendedPriorityFee( connection: Connection, accountKeys: string[], ): Promise<number> { const recentFees = await connection.getRecentPrioritizationFees({ lockedWritableAccounts: accountKeys.map(k => new PublicKey(k)), }); if (recentFees.length === 0) { return 1000; // Default fallback fee } // Use the 75th percentile of recent fees for reliable landing const sortedFees = recentFees .map(f => f.prioritizationFee) .sort((a, b) => a - b); const percentile75Index = Math.floor(sortedFees.length * 0.75); return sortedFees[percentile75Index]; } ``` ### 4.4 Compute Unit Budgeting Always set an explicit compute unit limit. The default is 200,000 CU, but many transactions use far less. Setting a tighter limit reduces the priority fee cost (priority fee = CU price * CU limit) and makes the transaction more likely to be included: ```typescript // If your transaction typically uses ~50,000 CU, set the limit to 60,000 // (with some headroom for variance) const computeLimitInstruction = ComputeBudgetProgram.setComputeUnitLimit({ units: 60000, }); ``` **Measure your transaction's actual CU usage** on devnet or via simulation before setting the limit. Setting it too low causes the transaction to fail. Setting it too high wastes priority fee budget. --- ## 5. Landing Rate Optimization ### 5.1 What Affects Landing Rate? A transaction's "landing rate" is the probability that it is included in a block within a given time window. Factors that affect landing rate: | Factor | Impact | Optimization | |--------|--------|-------------| | **Priority fee** | Higher fee = higher priority = better landing rate | Use dynamic fee estimation. Increase during congestion. | | **Compute unit limit** | Lower limit = less block space consumed = validators prefer it | Set a tight CU limit based on actual usage. | | **Transaction size** | Smaller transactions are easier to fit in blocks | Minimize account references. Use ALTs for complex transactions. | | **Submission timing** | Submitting at the right time in the leader schedule matters | Submit well before the leader's slot ends. Target early in the slot. | | **Connection quality** | Staked connections get preferential QUIC rate limiting | Use RPC providers with staked connections. | | **Retry strategy** | Retrying with updated blockhashes and fees improves eventual landing | Implement exponential backoff with fee adjustment. | ### 5.2 Retry Strategy Implement a robust retry strategy for important transactions: ```typescript const MAX_RETRIES = 5; const BASE_RETRY_DELAY_MS = 500; async function sendWithRetry( connection: Connection, transaction: Transaction, signers: Keypair[], basePriorityFee: number, ): Promise<string> { for (let attempt = 0; attempt < MAX_RETRIES; attempt++) { try { // Get fresh blockhash for each attempt const { blockhash, lastValidBlockHeight } = await connection.getLatestBlockhash('confirmed'); transaction.recentBlockhash = blockhash; transaction.lastValidBlockHeight = lastValidBlockHeight; // Increase priority fee on retries const retryFeeMultiplier = 1 + (attempt * 0.5); const priorityFee = Math.floor(basePriorityFee * retryFeeMultiplier); // Update priority fee instruction updatePriorityFee(transaction, priorityFee); // Sign and send transaction.sign(...signers); const signature = await connection.sendRawTransaction( transaction.serialize(), { skipPreflight: false, maxRetries: 0, // Handle retries ourselves } ); // Wait for confirmation const confirmation = await connection.confirmTransaction({ signature, blockhash, lastValidBlockHeight, }); if (!confirmation.value.err) { return signature; } } catch (error) { // Wait before retrying const delayMs = BASE_RETRY_DELAY_MS * Math.pow(2, attempt); await new Promise(resolve => setTimeout(resolve, delayMs)); } } throw new Error(`Transaction failed after ${MAX_RETRIES} attempts`); } ``` ### 5.3 Multi-Provider Submission For critical transactions, submit to multiple RPC providers simultaneously to increase the probability of reaching the current leader: ```typescript const RPC_PROVIDERS = [ 'https://provider-1.example.com', 'https://provider-2.example.com', 'https://provider-3.example.com', ]; async function sendToMultipleProviders( serializedTransaction: Buffer, ): Promise<string> { const connections = RPC_PROVIDERS.map(url => new Connection(url)); // Submit to all providers simultaneously const results = await Promise.allSettled( connections.map(connection => connection.sendRawTransaction(serializedTransaction, { skipPreflight: true, // Skip preflight to avoid RPC-specific issues }) ) ); // Return the first successful submission for (const result of results) { if (result.status === 'fulfilled') { return result.value; } } throw new Error('All RPC providers failed to accept transaction'); } ``` **Important:** When using multi-provider submission with `skipPreflight: true`, ensure the transaction has been validated locally or via simulation before submission. Skipping preflight means the RPC provider does not simulate the transaction before forwarding it. See [[rpc-security]] for guidance on selecting and managing multiple RPC providers. --- ## 6. Transaction Submission for Protocol Operations ### 6.1 Guardian/Emergency Operations When activating a circuit breaker (see [[circuit-breakers]]) or executing an emergency operation, landing speed is critical: - Use the highest priority fees the team is willing to pay - Submit to multiple RPC providers simultaneously - Consider using Jito bundles for guaranteed execution ordering - Pre-sign emergency transactions and keep them ready for immediate submission - Ensure the guardian hot wallet has sufficient SOL for high priority fees at all times ### 6.2 Keeper/Crank Operations Keepers and cranks (automated bots that perform protocol maintenance -- settling orders, updating prices, processing liquidations) have specific submission requirements: | Requirement | Detail | |-------------|--------| | **Consistent landing** | Keeper operations must land reliably. Use dynamic priority fees and retry logic. | | **Cost efficiency** | Keepers run continuously. High priority fees for every transaction add up. Optimize CU usage and fee estimation. | | **Monitoring** | Monitor keeper landing rates. A drop in landing rate means the keeper is not performing its function. See [[monitoring]]. | | **Hot wallet management** | Keeper wallets hold SOL for fees. Monitor balances and refill proactively. See [[hot-wallets]]. | | **Idempotency** | Keeper operations should be idempotent -- executing the same operation twice should not cause harm. This is critical when retrying. | ### 6.3 Frontend Transaction Submission When a frontend application submits transactions on behalf of users: - **Let the user set slippage.** Provide a default but allow customization. - **Show the user the expected outcome** before submission (via simulation). - **Implement retry logic** with user feedback (show transaction status, allow cancellation). - **Consider protected submission** for large swaps or high-value operations. - **Do not expose RPC credentials** in frontend code. Use a backend proxy for authenticated RPC access. - **Handle failed transactions gracefully.** Show the user what happened and what to do next. --- ## 7. Monitoring for MEV Extraction ### 7.1 Why Monitor for MEV? Even with protected submission paths and slippage protection, MEV extraction can still occur. Monitoring detects: - Whether your protections are working - New MEV vectors that your current protections do not cover - The volume and cost of MEV extraction affecting your protocol and users - Validators or RPC providers that may be front-running your transactions ### 7.2 What to Monitor | Metric | How to Measure | Alert Threshold | |--------|---------------|-----------------| | **Execution price vs. expected price** | Compare actual swap output to the expected output at the oracle price at execution time | Deviation > slippage tolerance on > 5% of transactions | | **Transaction ordering anomalies** | Check if your transactions are consistently preceded by similar transactions from unknown addresses | Pattern of frontrunning transactions in > 3% of slots | | **Sandwich detection** | Look for buy-sell pairs surrounding your transactions in the same slot, involving the same token pair | Any confirmed sandwich pattern | | **Bundle landing rate** | Track the percentage of submitted bundles that land successfully | Landing rate < 80% (investigate tip levels) | | **Priority fee trends** | Track median and p90 priority fees on the network | Sustained spikes indicating congestion or MEV competition | | **Liquidation success rate** | Track whether liquidation transactions execute successfully on first attempt | Success rate < 90% (investigate competition or front-running) | | **Value leaked to MEV** | Aggregate the difference between expected and actual execution across all protocol transactions | Rising trend indicates worsening MEV exposure | ### 7.3 MEV Monitoring Approaches | Approach | Description | Use Case | |----------|-------------|----------| | **Jito Explorer** | Jito's public dashboard showing bundle activity, tips, and MEV metrics | Understand overall Solana MEV landscape | | **Custom transaction analysis** | Parse your protocol's transactions and compare execution prices to oracle prices at the same slot | Detect per-transaction MEV extraction | | **Validator behavior analysis** | Track which validators include your transactions and whether ordering is consistent | Detect validator-level front-running | | **RPC latency monitoring** | Measure time between transaction submission and inclusion | Detect RPC-level delays that may indicate transaction forwarding to searchers | ### 7.4 Response to Detected MEV | Detection | Response | |-----------|----------| | Consistent sandwich attacks on user swaps | Tighten default slippage. Enable Jito bundle submission for user transactions. Consider transaction protection services. | | Liquidation front-running | Switch liquidation bots to Jito bundle submission. Increase priority fees. Consider private liquidation infrastructure. | | RPC provider front-running suspected | Switch RPC provider immediately. Report to the community. See [[rpc-security]]. | | Rising overall MEV extraction | Review and upgrade submission strategy. Consider dedicated submission infrastructure. | --- ## 8. Multisig and DAO Transaction Considerations ### 8.1 MEV Risks for Multisig Transactions Multisig transactions have unique MEV exposure because: - **Transaction contents are visible during the proposal stage.** A multisig proposal (e.g., a Squads proposal) reveals the transaction details to all signers and potentially to the public before execution. - **Execution timing is predictable.** Once sufficient signatures are collected, execution is imminent. - **Transaction size may be large.** Complex multisig operations (program upgrades, large treasury transfers) may be conspicuous. ### 8.2 Mitigations for Multisig MEV | Mitigation | Description | |------------|-------------| | **Execute via Jito bundle** | When the multisig transaction involves value-bearing operations (swaps, large transfers), execute the final transaction via a Jito bundle. | | **Time-lock with private execution** | Use a time-lock that gives the team a private execution window before public execution is allowed. | | **Protected execution bots** | Use a bot with protected submission to execute multisig transactions immediately after approval. | | **Split proposal from execution** | Keep sensitive details out of the proposal until execution time. | See [[multisigs]], [[squads]], and [[signing-workflow]] for comprehensive multisig security guidance. --- ## 9. Dedicated Submission Infrastructure ### 9.1 When to Build Dedicated Infrastructure Most protocols can rely on private RPCs and Jito bundles. Dedicated submission infrastructure is warranted when: - The protocol processes high volumes of value-bearing transactions (DEX, aggregator) - The protocol operates critical bots (liquidation, rebalancing) where failure has direct financial consequences - The protocol's MEV exposure exceeds the cost of dedicated infrastructure - The protocol requires sub-second latency for competitive operations ### 9.2 Components of Dedicated Infrastructure | Component | Purpose | Complexity | |-----------|---------|------------| | **Private RPC nodes** | Direct transaction submission without third-party exposure | Moderate. Requires running and maintaining RPC nodes. | | **Validator relationships** | Direct QUIC connections to validators for priority forwarding | High. Requires staked connections and validator partnerships. | | **Jito block engine integration** | Direct bundle submission to the Jito block engine | Moderate. Requires Jito relayer integration. | | **Dynamic priority fee engine** | Automatically adjusts priority fees based on network conditions | Moderate. Requires real-time fee monitoring and adjustment. | | **Transaction simulation pipeline** | Simulates transactions before submission to detect failures | Moderate. Requires simulation infrastructure. | | **Retry and escalation engine** | Automatically retries failed transactions with escalating priority | Moderate. Requires monitoring and alerting integration. | ### 9.3 Operational Requirements Dedicated submission infrastructure must be: - **Redundant:** Multiple RPC nodes, multiple Jito relayer connections, failover paths - **Monitored:** Landing rates, latency, error rates, priority fee effectiveness - **Secured:** Access controls on submission infrastructure, key management for signing, network security - **Maintained:** Software updates, validator list updates, Jito protocol updates --- ## 10. Common Mistakes | Mistake | Risk | Prevention | |---------|------|------------| | **No slippage protection on swaps** | Sandwich attacks extract unlimited value from the user. A large swap with no slippage limit can lose a significant percentage to MEV. | Always implement slippage protection. Set a `minimum_amount_out` for every swap. | | **Hardcoded priority fees** | During congestion, hardcoded fees are too low and transactions do not land. During calm periods, hardcoded fees are wasteful. | Use dynamic fee estimation based on recent network conditions. | | **No retry logic** | A single failed submission means the operation does not happen. For keepers and time-sensitive operations, this can cause protocol harm. | Implement retry with exponential backoff and fee escalation. | | **Submitting large treasury swaps through public RPC without protection** | The swap is visible to searchers who sandwich it, extracting value from the treasury. | Use protected submission (Jito bundles or private channels) for large treasury operations. | | **Ignoring compute unit limits** | Default 200,000 CU wastes priority fee budget. A transaction that uses 50,000 CU at 10,000 micro-lamports/CU costs 4x more than necessary. | Measure actual CU usage and set tight limits with reasonable headroom. | | **Not monitoring transaction landing rates** | Keeper operations silently fail. Protocol functions degrade without anyone noticing. | Monitor landing rates for all automated operations. Alert on degradation. | | **Using a single RPC provider for critical operations** | If the provider goes down, all operations halt. | Use multiple RPC providers. Implement fallback logic. See [[rpc-security]]. | | **Exposing RPC API keys in frontend code** | Anyone can extract the API key and use the team's RPC quota. | Use a backend proxy for authenticated RPC access. | | **Not maintaining sufficient SOL in keeper/guardian wallets** | The wallet runs out of SOL for fees. Emergency operations fail because the guardian cannot pay for the transaction. | Monitor wallet balances. Set up alerts and automatic refills. See [[hot-wallets]]. | | **Retrying without updating the blockhash** | Retrying with an expired blockhash means the transaction can never land. | Get a fresh blockhash for each retry attempt. | | **Skipping preflight simulation when not using multi-provider** | Without preflight, you submit a transaction that will fail on-chain, wasting fees. | Only skip preflight when you have validated the transaction through other means (local simulation) or when using multi-provider submission. | --- ## Relevant Controls The following controls from the [[general/control-registry|Control Registry]] apply to this topic. Refer to the Control Registry for level-specific requirements (L1/L2/L3/L4). Relevant control families: **SOS-SUB**. --- ## References - [Jito Documentation](https://jito-labs.gitbook.io/mev/) - [Solana Transaction Processing](https://docs.solanalabs.com/validator/tpu) - [Solana Priority Fees](https://docs.solanalabs.com/developing/guides/advanced/how-to-use-priority-fees) - [[rpc-security]] -- RPC provider trust, privacy, and multi-provider strategy - [[hot-wallets]] -- Bot wallets, relayers, cranks -- limits and rotation - [[monitoring]] -- On-chain and off-chain monitoring and alerting - [[circuit-breakers]] -- Emergency stop and program state management - [[oracle-integration]] -- Secure price feed consumption and manipulation resistance - [[multisigs]] -- Multisig configuration and operational security - [[signing-workflow]] -- Transaction signing procedures and verification - [[squads]] -- Squads Protocol v4 multisig configuration and security --- *This article is part of the [[README|SOS Standard Security Knowledge Base]]. For the complete standard, see [[general/sos-standard|SOS Standard]].*