A bot that handles classic SPL tokens correctly does not partially handle Token-2022. ★It works completely on some tokens and fails completely on others, with nothing in between.★
That is actually good news, because it means the integration is a finite list rather than an ongoing tax.
The Five Hardcoded Assumptions
Every classic-token bot contains these, usually without noticing:
TOKEN_PROGRAM_ID // ★assumed constant★
getAssociatedTokenAddress(mint, owner) // ★program ID omitted★
{ dataSize: 165 } // ★assumed account size★
minOut = expected * (1 - slippage) // ★assumes full amount arrives★
createTransferInstruction(...) // ★classic-only builder★
★Each one works perfectly until it meets a Token-2022 mint, then fails in a way that does not name the assumption.★
Fix Them In This Order
The order matters, because fixing them out of sequence produces a bot that half-works in confusing ways.
1. Resolve the program ID from the mint. Everything else depends on this being available.
async function resolveToken(connection, mint) {
const info = await connection.getAccountInfo(mint);
if (!info) throw new Error("mint not found");
return { programId: info.owner, is2022: info.owner.equals(TOKEN_2022_PROGRAM_ID) };
}
★Cache it — a mint's owning program never changes.★ Store it alongside the mint address everywhere you track a token.
2. Thread it through every derivation and builder.
const ata = await getAssociatedTokenAddress(mint, owner, false, programId);
const ix = createTransferInstruction(src, dst, owner, amount, [], programId);
★Omitting the parameter defaults to classic★, which is why this failure is silent on classic tokens and total on Token-2022 ones.
3. Query both programs for balances.
const [a, b] = await Promise.all([
connection.getParsedTokenAccountsByOwner(wallet, { programId: TOKEN_PROGRAM_ID }),
connection.getParsedTokenAccountsByOwner(wallet, { programId: TOKEN_2022_PROGRAM_ID }),
]);
4. Screen extensions before trading. Skip non-transferable and permanent delegate; adjust for transfer fee, hook, and default frozen state.
5. Adjust the fee math last. It depends on step 4 having read the config.
★Doing step 5 before step 1 is the common mistake★ — you cannot compute a transfer fee for a mint whose program you have not resolved.
If your Token-2022 support is complete and transactions still miss, a free BoltTx key is one line to test the submission path.
Where It Costs You Latency
For a sniper, the honest accounting:
One extra account read — the mint, which gives you both the program ID and the extension data in a single fetch. ★You were probably reading the mint anyway for decimals.★
Nothing extra for classic tokens. The owner check short-circuits immediately, so the majority of tokens cost you one comparison.
Simulation for hooked tokens — genuinely expensive, and the reason hooked tokens are usually worth skipping in a speed-sensitive strategy.
★The integration does not slow down your existing flow. It adds a branch that most tokens do not take.★
The Testing Problem
You cannot verify this on devnet against real tokens, because the tokens you care about do not exist there.
What works instead:
// ★Create your own test mints with each extension.★
await createMint(connection, payer, authority, null, 9,
Keypair.generate(), undefined, TOKEN_2022_PROGRAM_ID);
Create one mint per extension you claim to support, then run your full trade path against each. ★A bot that has never executed against a fee-bearing mint has untested fee math, regardless of how carefully it was written.★
Test the sell, not just the buy. Non-transferable tokens and selectively-reverting hooks both look fine on acquisition and fail on exit — which is the expensive direction to discover in production.
What Stays Exactly the Same
Worth stating, because it bounds the work:
- ★Transaction structure, signing, and the 1232-byte limit★
- ★Blockhash handling, expiry, and retry behaviour★
- ★Compute budget instructions and fee derivation★
- Account layout for the first 165 bytes
- ★Everything about submission and landing★
★Token-2022 is a token-layer change, not a transaction-layer one.★ Your retry loop, your fee policy, and your submission path are untouched — which is why this integration is finite.
A Verification Checklist
□ Program ID resolved from mint owner, never assumed
□ Program ID passed to every ATA derivation
□ Program ID passed to every instruction builder
□ Balance queries cover both programs
□ ★dataSize filters do not assume 165★
□ Extensions screened before trading
□ ★Transfer fee subtracted before slippage★
□ Hook accounts assembled via the async builder
□ Non-transferable and permanent delegate rejected
□ ★Sell path tested, not just buy★
□ Rent computed from actual account size
★The starred lines are the ones that fail silently.★ The others produce an error that points somewhere near the problem.
What Landing Looks Like
Real transactions through our delivery nodes: median confirmation 336ms — under one slot.
★Token-2022 support changes whether your transaction is correct, not how fast it lands.★ Those are separate problems with separate fixes, and a correct transaction still competes for inclusion like any other.
Where BoltTx Fits
We handle submission, which Token-2022 does not change at all.
Submissions route through our own delivery nodes in four regions with stake-weighted routing and no public mempool exposure, so a transaction is not observable in transit before it lands. Whether your instructions reference the classic or the 2022 token program makes no difference to us — we transmit the bytes you signed.
You sign locally. We never hold funds, never sign, and never modify transaction contents. The tip travels inside the transaction, paid on chain from your own wallet, and reverts with the transaction if it fails, because that is how Solana handles atomic transactions. You pay only on transactions that reach the chain.
Get a free API key. No monthly fee:
const connection = new Connection("https://la.bolttx.io/?api-key=YOUR_KEY");
FAQ
How do I add Token-2022 support to an existing bot? Resolve the program ID from the mint owner, thread it through every derivation and instruction builder, query both programs for balances, screen extensions, then adjust fee math. The order matters.
What breaks first when a classic bot meets a Token-2022 token?
Usually the ATA derivation, since the program ID is part of it. You get AccountNotFound for an account that exists at a different address than the one you computed.
Do I need to rewrite my retry and fee logic? No. Token-2022 is a token-layer change. Transaction structure, blockhash handling, retries, compute budget, and submission are all unchanged.
How much latency does Token-2022 support add? Almost none. The mint read gives you both the program ID and extension data in one fetch, and classic tokens short-circuit on the owner comparison.
How do I test Token-2022 handling? Create your own test mints on devnet, one per extension you support, and run the full trade path against each. Real tokens with these extensions will not exist on devnet.
Why must I test the sell path specifically? Because non-transferable tokens and selectively-reverting hooks both succeed on acquisition and fail on exit. Testing only buys leaves the expensive failure undiscovered.
Should I support transfer hooks? Only when the hook program is verifiable and both trade directions simulate cleanly. For speed-sensitive strategies, skipping hooked tokens is usually the better tradeoff.
Which extensions should my bot reject outright? Non-transferable and permanent delegate. One prevents selling and the other lets a third party take your position, and neither can be handled with better code.
Why is my balance query missing tokens after adding Token-2022? You are probably still making one query. There is no combined call, so both program IDs need separate queries whose results you merge.
Do I need to change my dataSize filters? Yes if they assume 165 bytes. Extended accounts are larger, so an exact-size filter silently excludes every Token-2022 account carrying extensions.
How do I handle the transfer fee in slippage? Subtract the fee from the expected output before applying tolerance. Doing it the other way around reverts deterministically whenever the fee exceeds your slippage.
Should I cache the program ID per mint? Yes, indefinitely. A mint's owning program never changes, so it belongs in whatever structure you use to track a token, alongside its decimals.
What if an aggregator handles Token-2022 for me? Verify with a small trade rather than assuming. Support varies by protocol and by extension, and transfer hooks in particular require explicit handling.
Does Token-2022 affect transaction size? Indirectly. Hook tokens add accounts at 32 bytes each, which can push a multi-hop route past the 1232-byte limit that it previously fit inside.
Is it worth supporting Token-2022 at all? Depends on what you trade. If new launches on your target platform use it, yes. If not, screening to reject those tokens cleanly is a valid alternative to full support.
What is the minimum viable Token-2022 support? Resolve the program ID, thread it through, query both programs, and reject any mint carrying extensions you have not implemented. That is safe without being complete.