Proposal: add a generic passthrough swap variant for custom AMM execution

We are requesting a small change to jupiter-amm-interface that would let Jupiter’s on-chain aggregator execute swaps for protocols that use non-standard instruction formats.

This is an engineering interface request. Not a treasury ask. Not a governance vote.

Problem
Jupiter integration has two phases:

  1. Off-chain routing: adapters implement the Amm trait (quote, update, get_swap_and_account_metas). This is protocol-agnostic and works for any adapter.
  2. On-chain execution: Jupiter’s aggregator reads a Swap enum variant and uses it to construct CPI instruction data in a hardcoded format per protocol. There are 96 protocol-specific variants as of v0.6.1.

Phase 2 has no generic option. Every new protocol needs Jupiter to add a bespoke variant, write a bespoke match arm, and redeploy the on-chain program.

For protocols using Anchor-format instructions (8-byte discriminator + custom args), no existing variant produces the correct byte layout. The adapter builds correct instruction data off-chain, but Jupiter’s on-chain program overwrites it with a hardcoded format the target program cannot deserialize.

Context: BurnRouter
BurnRouter is a deployed Solana program for PIGEON token sell-to-burn routing. We have a complete Amm trait implementation:

quote(), update(), get_swap_and_account_metas() — all working

62 adapter tests, 49 on-chain program tests passing

Jupiter’s routing binary can discover, quote, and evaluate BurnRouter routes today
On-chain execution fails because no Swap variant produces Anchor-format CPI data. BurnRouter expects 25 bytes (8-byte Anchor discriminator + amount_in + min_out + venue_id). The nearest variant (TokenSwap) sends SPL Token Swap format…wrong discriminator size, wrong argument offsets, missing fields. Every byte mismatches.

We also have a working direct execution path that bypasses Jupiter entirely, so this is not blocking our operation, only blocking Jupiter-native execution.

Proposed Change
Add one variant to the Swap enum:

ExternalAmm {
instruction_data: Vec,
}

Add one match arm that passes instruction_data through to invoke() with adapter-provided account metas.

Scope: approximately 5 lines in the interface crate, 15-20 lines in the on-chain program. Zero changes to existing variants.

Why This Is Minimal

No existing integrations affected

Borsh serialization handles the new variant automatically

The adapter already constructs complete instruction data in get_swap_and_account_metas()

Same trust model as account metas: adapters provide them, Jupiter uses them.

Security Considerations
Jupiter already trusts adapters to return correct account metas. ExternalAmm extends this to instruction data, same trust surface. Possible mitigations: program ID allowlist, additional adapter review, instruction data length cap.

Who This Helps

Any custom AMM using Anchor or a non-standard instruction format. The Swap enum has nearly doubled in recent versions (from ~50 to 96). A generic passthrough reduces per-protocol maintenance for Jupiter’s own team while opening the door for more protocols.

Supporting Material

Blocker explanation: pigeon-burn-router/BLOCKER_JUPITER_EXECUTION.md at main · level941-pigeon/pigeon-burn-router · GitHub

Byte-level mismatch proof: pigeon-burn-router/SWAP_ENUM_MISMATCH.md at main · level941-pigeon/pigeon-burn-router · GitHub

Patch proposal with code: pigeon-burn-router/JUPITER_PATCH_PROPOSAL.md at main · level941-pigeon/pigeon-burn-router · GitHub

Proof-of-concept fork with tests: pigeon-burn-router/jupiter-fork-proof/jupiter-amm-interface-patched at main · level941-pigeon/pigeon-burn-router · GitHub

Review packet: pigeon-burn-router/JUPITER_REVIEW_PACKET.md at main · level941-pigeon/pigeon-burn-router · GitHub

Ask
We are asking Jupiter to consider adding a generic execution passthrough for custom AMM programs. This is a small change that solves a structural bottleneck, not just for BurnRouter, but for any protocol that needs Jupiter routing with a non-standard instruction format.

We have done the engineering work on our side and are ready to test and validate immediately if this variant is added.

Thank you for reviewing.

5 Likes

I’ve reviewed the proposal and, while I’m not a developer, the logic for a “Generic ExternalAmm” seems like a win-win for the Jupiter ecosystem:

The Problem: Current hardcoded “plugs” (Swap variants) are too rigid for new protocols like BurnRouter that use different data formats (Anchor).

The Solution: Instead of building a new “plug” for every project, create one Universal Socket (ExternalAmm) that can pass any data directly.

Pros: * Future-proofing: No more waiting for Jupiter to manually update its code for every new AMM.

Simplicity: Very small code change (~25 lines) with high impact.

Growth: Fixes the bottleneck for PIGEON’s sell-to-burn routing immediately.

Cons: * Requires basic security guards (like an allowlist) to ensure the data sent is safe.

I fully support this update to make Jupiter more flexible for the next wave of Solana protocols!

2 Likes