Skip to content

Minimal Anchor program to execute external Solana instructions (CPI) with dynamic data and caller-specified accounts.

Notifications You must be signed in to change notification settings

kyoshoku/amm-executor

Repository files navigation

AMM Executor (Anchor)

A minimal Solana program built with Anchor that executes external program instructions (CPI) with dynamic instruction data and a caller-provided list of remaining accounts.

What it does

  • Exposes execute_swap(ctx, instruction_data: Vec<u8>)
  • Builds a Solana Instruction for the specified external_program using:
    • instruction_data bytes you pass to the method
    • remaining_accounts forwarded as AccountMeta[] in the same order
  • Invokes the target program via invoke.

Interface (IDL excerpt)

{
  "name": "execute_swap",
  "accounts": [
    { "name": "user", "writable": true, "signer": true },
    { "name": "external_program" }
  ],
  "args": [
    { "name": "instruction_data", "type": "bytes" }
  ]
}

Program accounts (Anchor)

  • user: signer who pays for the transaction / invoking user.
  • external_program: unchecked program ID of the target to call.
  • remaining_accounts: all other accounts required by the external instruction in the exact order expected by that program.

Build

anchor build

Local test (if applicable)

anchor test

Deploy

Update Anchor.toml as needed and then:

anchor deploy

Client usage (TypeScript)

import { Program, AnchorProvider, web3 } from "@coral-xyz/anchor";

// program: Program<AmmExecutor>
// externalProgramId: web3.PublicKey
// accounts required by the target instruction in the correct order
const remainingAccounts: web3.AccountMeta[] = [
  { pubkey: acct1, isWritable: true, isSigner: false },
  { pubkey: acct2, isWritable: false, isSigner: false },
  // ...
];

// Build the exact bytes required by the target program's instruction
// Keep this payload small; prefer accounts for large data.
const instructionData = Buffer.from([/* ... encoded ix data ... */]);

await program.methods
  .executeSwap([...instructionData]) // bytes -> number[] or Buffer also works
  .accounts({
    user: provider.wallet.publicKey,
    externalProgram: externalProgramId,
  })
  .remainingAccounts(remainingAccounts)
  .rpc();

Notes and constraints

  • Ensure remaining_accounts exactly matches the target program's expected order and flags.
  • Keep instruction_data small (hundreds of bytes). For larger payloads, store data in an account and pass that account instead.

Troubleshooting

  • Error: memory allocation failed, out of memory
    • Reduce instruction_data size
    • Pass only the necessary remaining_accounts and ensure correct order
    • If the target program expects big data, write it into an account and pass the account

Security considerations

  • external_program is UncheckedAccount; callers control which program is invoked. Gate or restrict at the client/transaction layer as needed.

License

MIT

About

Minimal Anchor program to execute external Solana instructions (CPI) with dynamic data and caller-specified accounts.

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published