Skip to content

Relay a Solana transaction

This guide shows how to relay a SOL transfer or a raw Solana instruction through the same submit endpoints used for EVM chains. Photon's relayer acts as the fee payer, so your users never need SOL for fees.

Prerequisites

How the fields map on Solana

Use POST https://photon.example.com/api/submit-tx (or submit-tx-sync) with:

Field Solana meaning
chainId 10100001 (Solana Devnet).
to Base58 public key of the recipient (or program, for raw instructions).
value Lamports, as a base-10 integer string. Must fit in an unsigned 64-bit integer.
callData "" or "0x" for a plain SOL transfer; otherwise a base64-encoded JSON instruction (below).

EVM-only fields — gasPrice, maxFeePerGas, maxPriorityFeePerGas, gasLimit, and authorizationList — are ignored on Solana. The network fee is 5000 lamports per signature, and relayed transactions carry a single signature (the relayer's), so the cost estimate is 5000 + value lamports.

1. Relay a plain SOL transfer

Leave callData empty (or "0x") and set value to the lamports to send:

curl -X POST https://photon.example.com/api/submit-tx \
  -H "api-key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "to": "9aE476sH92Vz7DMPyq5WLPkrKWivxeuTKEFKd2sZZcde",
    "callData": "",
    "chainId": 10100001,
    "value": "1000000000"
  }'
const res = await fetch("https://photon.example.com/api/submit-tx", {
  method: "POST",
  headers: { "api-key": "YOUR_API_KEY", "Content-Type": "application/json" },
  body: JSON.stringify({
    to: "9aE476sH92Vz7DMPyq5WLPkrKWivxeuTKEFKd2sZZcde",
    callData: "",
    chainId: 10100001,
    value: "1000000000", // 1 SOL
  }),
});
const { data } = await res.json();
console.log(data.txId);

2. Relay a raw instruction

To call a program, describe one instruction as JSON, then base64-encode the whole JSON document into callData:

{
  "programId": "MemoSq4gqABAXKb96qnH8TysNcWxMyWCqXgDLGmfcHr",
  "keys": [
    { "pubkey": "9aE476sH92Vz7DMPyq5WLPkrKWivxeuTKEFKd2sZZcde", "isSigner": false, "isWritable": false }
  ],
  "data": "aGVsbG8gZnJvbSBQaG90b24="
}
  • programId — base58 program address (required).
  • keys — account metas; isSigner and isWritable default to false.
  • data — the instruction data, itself base64-encoded.
const instruction = {
  programId: "MemoSq4gqABAXKb96qnH8TysNcWxMyWCqXgDLGmfcHr",
  keys: [],
  data: Buffer.from("hello from Photon").toString("base64"),
};

const res = await fetch("https://photon.example.com/api/submit-tx", {
  method: "POST",
  headers: { "api-key": "YOUR_API_KEY", "Content-Type": "application/json" },
  body: JSON.stringify({
    to: instruction.programId, // still required; not used to build the instruction
    callData: Buffer.from(JSON.stringify(instruction)).toString("base64"),
    chainId: 10100001,
    value: "0",
  }),
});

Warning

The relayer's fee-payer key is the only signer. Any account marked isSigner: true other than the fee payer will fail signature verification, so raw instructions must not require additional signers.

3. Check status

Status flow is identical to EVM: poll GET https://photon.example.com/api/tx?id=<txId>. On Solana, executionTxHash is the base58 transaction signature, and the transaction reports EXECUTED once it reaches confirmed commitment.