LayerHopdocs

Concepts

The submitViaApi flow

Why some Solana transactions must be signed by the wallet but submitted through POST /v1/orders/submit, and how to do it.

Open in ClaudeOpen in ChatGPT

What the flag means#

A Solana transaction (vm: "svm") can come with submitViaApi: true. Then the wallet must only sign it. Do not broadcast it to an RPC node; send the signed bytes to POST /v1/orders/submit and LayerHop forwards them to the provider.

JSON
{ "vm": "svm", "serializedTx": "AQAAAA…", "submitViaApi": true }

Why#

Today this applies to Jupiter. Jupiter's best routes are often RFQ quotes (a market maker co-signs the transaction) or gasless swaps (Jupiter pays the fee and co-signs). Those transactions only become valid when the provider adds its signature, so a plain RPC broadcast will never land them. Jupiter executes every order it builds through its own endpoint, so LayerHop marks all Jupiter transactions submitViaApi: true.

Flow#

  1. POST /v1/orders → { vm: "svm", serializedTx, submitViaApi: true }.
  2. Deserialize, sign with the user's wallet, serialize, base64-encode.
  3. POST /v1/orders/submit with { quoteId, signedTransaction }.
  4. The response is { provider, txHash } — the Solana transaction signature.
TypeScript
import { VersionedTransaction } from "@solana/web3.js";

const tx = await lh.buildTx(quote.quoteId);
if (tx.vm === "svm") {
  const signed = await wallet.signTransaction(VersionedTransaction.deserialize(Buffer.from(tx.serializedTx, "base64")));
  const b64 = Buffer.from(signed.serialize()).toString("base64");
  const signature = tx.submitViaApi
    ? await lh.submit(quote.quoteId, b64)                       // through LayerHop
    : await connection.sendRawTransaction(signed.serialize());  // straight to the network
}

Rules#

  • Calling submit for a quote whose provider broadcasts from the wallet returns INVALID_PARAMS.
  • Submit within seconds. If the provider rejects the transaction (price moved, quote stale) you get PROVIDER_ERROR; get a new quote and sign again.
  • LayerHop only relays the bytes your user signed. It cannot change them, and it never sees a private key.