feat(kora): add swap_gas plugin + plugin infrastructure#383
feat(kora): add swap_gas plugin + plugin infrastructure#383dev-jodee wants to merge 19 commits intorelease/2.2.0from
Conversation
Add a trait-based swap quote provider abstraction with Jupiter default and config-driven spread for swap-for-gas quotes. Implement the swapForGas JSON-RPC method to build token-for-SOL transactions with optional Kora fee-payer signing and no user transaction co-signing. Wire config/method enablement, RPC docs, and TypeScript SDK/plugin request-response types with tests. Refs: PRO-932
📊 TypeScript Coverage ReportCoverage: 33.1% View detailed reportCoverage artifacts have been uploaded to this workflow run. |
Greptile SummaryThis PR adds a new Key changes:
Issues found:
Confidence Score: 3/5
Important Files Changed
Sequence DiagramsequenceDiagram
participant Client
participant KoraRPC
participant SwapForGas
participant QuoteProvider
participant PriceOracle
participant RpcClient
participant Signer
Client->>KoraRPC: swapForGas(request)
KoraRPC->>SwapForGas: swap_for_gas(rpc_client, request)
SwapForGas->>SwapForGas: validate lamports_out > 0
SwapForGas->>SwapForGas: validate source/destination wallets (disallow list)
SwapForGas->>SwapForGas: validate_lamport_fee(lamports_out)
SwapForGas->>SwapForGas: check fee_token is supported
SwapForGas->>QuoteProvider: quote_token_amount_in_for_lamports_out(rpc_client, token_mint, lamports_out, config)
QuoteProvider->>PriceOracle: get_token_price(token_mint)
PriceOracle-->>QuoteProvider: TokenPrice { price, block_id }
QuoteProvider->>RpcClient: get_slot() [staleness check]
RpcClient-->>QuoteProvider: current_slot
QuoteProvider->>QuoteProvider: calculate_token_amount_in (ceil)
QuoteProvider-->>SwapForGas: quoted_token_amount
SwapForGas->>SwapForGas: apply_spread_bps(quoted_token_amount, spread_bps)
SwapForGas->>RpcClient: check source ATA exists
SwapForGas->>RpcClient: check destination ATA exists
SwapForGas->>SwapForGas: build instructions (token transfer + SOL transfer)
SwapForGas->>RpcClient: get_or_fetch_latest_blockhash()
SwapForGas->>SwapForGas: build VersionedMessage (Legacy)
alt sign_swap_transaction = true
SwapForGas->>Signer: sign_transaction_for_bundle()
Signer-->>SwapForGas: signed transaction
end
SwapForGas-->>KoraRPC: SwapForGasResponse
KoraRPC-->>Client: SwapForGasResponse
|
- use injected config for Jupiter staleness checks in swap quote provider - reject swap_for_gas Mock provider when swapForGas is enabled - add validator test for Mock-provider rejection path Refs: PRO-932
Trim self-explanatory comments from swap config/method/provider changes while keeping API docs where helpful. Refs: PRO-932
Add swap-for-gas RPC integration tests, replace the default spread literal with a shared constant, and allow mock quote provider in test harnesses via env override while keeping production validation strict by default. Refs: PRO-932
Prevent swapForGas requests from using the Kora signer as source_wallet, which could otherwise allow a self-token-transfer plus signer-funded SOL transfer path when pre-signing is enabled. Add an integration regression test that exercises this rejection path. Refs: PRO-932
Treat swap_for_gas.quote_provider = Mock the same way as validation.price_source = Mock: allow it with a production warning instead of requiring an env override. Remove the temporary KORA_ALLOW_MOCK_SWAP_QUOTE_PROVIDER test-runner/env path and update validator tests accordingly. Refs: PRO-932
Replace swap-for-gas API flow with dedicated sign and sign-and-send methods. Use a swap-specific signAndSend path to validate signer consistency and submit user-signed transactions. Update config flags, integration tests, and TypeScript SDK/plugin/types to the new method names. Refs: PRO-932
Ignore local pnpm store and replace legacy swap_for_gas method toggle with sign_swap_for_gas and sign_and_send_swap_for_gas. Refs: PRO-932
Refactor swap-for-gas RPC handlers to share validation/business logic in a processor, and enforce prebuilt transaction validation in signAndSendSwapForGas before Kora signing and forwarding. Add integration coverage for signAndSendSwapForGas with user signature flow and missing Kora signature slot recovery. Refs: PRO-932
Hard-rename the swap endpoint to swapForGas, remove signAndSendSwapForGas, and keep only build+partial-sign flow for gas swaps. Update Rust config/validator surfaces, integration fixtures/tests, and TypeScript SDK/plugin/types/tests to match the new API. BREAKING CHANGE: signSwapForGas and signAndSendSwapForGas are removed. Use swapForGas. Refs: PRO-932
Add swapForGas to DEFAULT_PROTECTED_METHODS so reCAPTCHA protects it by default, and update the config example comment accordingly. Refactor swap processor into focused helper methods and keep signing local to swap flow to avoid BundleSigner coupling. Refs: PRO-932
Prevent swapForGas from building transactions where destination_wallet is the Kora signer, which could otherwise collect user tokens without net SOL payout. Add integration coverage for destination_wallet == signer rejection. Refs: PRO-932
- remove swap-specific quote provider and use validation.price_source\n- hard-rename spread_bps to buffer_bps and lamports_out request/response fields\n- add swap_for_gas.max_lamports_out and max_token_amount_in guard\n- remove swapForGas signer_key/sig_verify options\n- update Rust + TS + integration tests for new contract Refs: PRO-932
remove the dedicated swapForGas RPC path and wire gas-swap validation through plugin execution in sign/signAndSend transaction and bundle flows. BREAKING CHANGE: swapForGas has been removed. Enable gas swap rules via kora.plugins.enabled = ["gas_swap"] on existing signing RPC methods. Refs: PRO-932
make bundle plugin execution optional and disable it for estimateBundleFee so plugin rules remain scoped to sign/signAndSend flows. also move the gas_swap plugin implementation into plugin_gas_swap.rs to keep plugin runner wiring focused in plugin/mod.rs. Refs: PRO-932
dispatch validation by outer program id, reject any non-swap outer instruction, and require exactly one system transfer plus one token transfer without re-uncompiling instructions. Refs: PRO-932
switch gas_swap semantic validation to VersionedTransactionResolved parsed system/spl instruction getters and keep strict outer-shape gating for exactly one system + one token instruction. Refs: PRO-932
Summary
swapForGasAPI approach with plugin-based transaction validation in existing signing flows.gas_swap, for gas-station swap shape enforcement.swapForGasRPC/module/SDK surface before release.Changes
signTransactionsignAndSendTransactionsignBundlesignAndSendBundlegas_swapplugin with strict outer-instruction rules:TransferorTransferWithSeed) from fee payerestimateBundleFeeskips plugin executioncrates/lib/src/plugin/plugin_gas_swap.rsfor cleaner separation.[kora.plugins] enabled = ["gas_swap"].swapForGasendpoint/module paths and related SDK/API surface that are no longer part of final design.Testing
just fmtjust checkjust testcargo test -p kora-lib gas_swap_ -- --nocapturecargo test -p kora-lib test_estimate_bundle_fee_skips_plugins -- --nocaptureCloses PRO-932
Closes https://linear.app/solana-fndn/issue/PRO-932/add-swapgas-station-api-endpoint-to-kora
📊 Unit Test Coverage
Unit Test Coverage: 83.6%
View Detailed Coverage Report