Corvus Labs

Falcon tips & transaction requirements

Exactly what Falcon accepts as a tip on a Solana transaction: instruction shape, allowed accounts, the 1,000,000 lamport minimum and the 1,232-byte cap.

Falcon checks every transaction before it forwards anything. Yours has to deserialize cleanly, carry as many signatures as its message header requires, fit in 1,232 bytes, and pay a tip that matches all four rules below.

Tip selection

A tip only counts when one top-level instruction meets every condition at once:

ConditionDetail
ProgramSystem Program
Instructiontransfer: the plain 8-byte-lamports transfer, not transferWithSeed
RecipientOne of the tip accounts, present in the transaction's static account keys
AmountAt least 1,000,000 lamports, in one instruction

That rules out several arrangements that look like they should work:

  • Amounts never add up. Falcon walks the instructions in order and takes the first System transfer to an allowed tip account that already meets the minimum. Two half-sized transfers qualify as neither.
  • Address lookup tables don't work for the tip. The recipient is matched against static account keys only.
  • A CPI tip doesn't count. The transfer has to be an instruction in the transaction you submit, not something your program does internally.
  • A tip declared in an HTTP field, a header or a client variable means nothing. Only the instruction is read.

Amount and accounts

The minimum tip is 1,000,000 lamports (0.001 SOL), paid in one transfer to any of these accounts:

Fa1con11xLjPddfzRwRUB16sbFZggp2JeJkCeWREyR8X
Fa1con11TM1RuAQzbQzYjTy4Ekfap9Lnc9fnEbQYEd6Q
Fa1con113Bvi76nS5AzUiRDC2fqjfzkNMUNRLgQybMYt
Fa1con1QGHJK232s8yZpzZZwqPexnAKcoyKj626LNsMv
Fa1con1zUzb6qJVFz5tNkPq1Ahm8H1qKW7Q48252QbkQ
Fa1con16d3MSwd3SAiwvr2LwgkpE7ot8zntbpuec8HAx
Fa1con1i7mpa7Qc6epYJ6r4P9AbU77DFFz173r59Df1x
Fa1con18nWn8TdAGL7JX8PertfMUGVSc899NawokJ4Bq
Fa1con1GKusK2EqsfzrDzGPaYZSxQtFGzJiRMMU9Zm2g
Fa1con1RDwVwM9VrJ53CwVefD3VU9c58EMpDawV7fLMi

Pick one at random per transaction: tipping the same account from everywhere makes every transaction compete for one write lock.

A JSON-RPC tip rejection comes back as -32602 transaction does not include required tip with "data":{"minimumLamports":N}. N is the required minimum; trust it over a hard-coded value.

Every other requirement

RequirementRuleFailure
SerializationStandard Solana transaction wire bytes, legacy or v0could not deserialize transaction
Trailing bytesNone; the buffer must end exactly where the transaction endscould not deserialize transaction
Size≤ 1,232 serialized bytestransaction exceeds maximum size of 1232 bytes
SignaturesAt least one, and never more than 127transaction has no valid signature
Signature countMust equal num_required_signatures in the message headertransaction signature count does not match required signatures, with "data":{"expected":n,"actual":n}

Falcon checks the signature count, not the signatures themselves. A partially signed transaction serialized with placeholder slots for the missing signers still carries the expected count, so Falcon forwards it and it fails on chain instead. Only a signature array that doesn't match num_required_signatures (or holds 0, or more than 127) is rejected here. Signatures are verified cryptographically in exactly one place: preflight simulation, which runs when you set skipPreflight: false.

Add the tip in TypeScript

import { PublicKey, SystemProgram, Transaction } from '@solana/web3.js';

const tipAccount = process.env.FALCON_TIP_ACCOUNT;
const tipLamports = Number(process.env.FALCON_MIN_TIP_LAMPORTS);

if (!tipAccount) {
  throw new Error('Set FALCON_TIP_ACCOUNT');
}
if (!Number.isSafeInteger(tipLamports) || tipLamports < 1_000_000) {
  throw new Error('FALCON_MIN_TIP_LAMPORTS must be at least 1000000');
}

const transaction = new Transaction();

// 1. Your application instructions.

// 2. The tip: a top-level System Program transfer.
transaction.add(
  SystemProgram.transfer({
    fromPubkey: payer.publicKey,
    toPubkey: new PublicKey(tipAccount),
    lamports: tipLamports,
  }),
);

// 3. Fee payer + fresh blockhash, then sign, then serialize.

The tip is an ordinary instruction, so the lamports only move if the transaction executes on chain.

Symptom → cause → fix

SymptomCauseFix
transaction does not include required tip (or SubmitError::MissingTip) with a tip you believe is thereThe transfer is below minimumLamports, the recipient is not one of the tip accounts, or the recipient came from an ALTUse data.minimumLamports, an account from the list, and put the recipient in the static account keys
Tip rejected only on some transactionsThe tip was split across instructions, so no single transfer reaches the minimumPay the whole tip in one transfer
transaction signature count does not match required signaturesA required signer is missing, or the message was edited after signingRebuild, sign with all signers, serialize once
could not deserialize transaction: verify encoding and formatWrong encoding, base64 sent as base58, or extra bytes appendedMatch encoding to the string you send; submit the exact serialized bytes
transaction exceeds maximum size of 1232 bytes after adding the tipThe tip pushed you over the capDrop an instruction, use an ALT for application accounts (not the tip), or split the work
Nothing happens at all on UDPAny of the aboveReproduce the same transaction over JSON-RPC to see the real reason

Per-transport response shapes are on Falcon errors & retries.

On this page