Skip to main content
The solData criterion provides advanced validation of Solana transaction instruction data using Interface Definition Language (IDL) specifications. It decodes and validates instruction parameters against specific rules before signing, and applies to API key authentication wallets only. For general policy setup, see the Policy Engine Overview. For common Solana policy patterns, see Solana Policies.

How solData works

A solData criterion specifies which Solana programs to validate via the idls field, then defines instruction-level validation rules via the conditions field. The idls field accepts either:

IDL specifications

Anchor IDL format

IDL specifications must follow Anchor’s IDL format v0.30+. To convert older formats:
anchor idl convert path/to/idl.json -o path/to/idl.json

Supported argument types

Primitive types supported: bool, string, pubkey, u8u256, i8i256, f32, f64. Complex types (user-defined types, arrays, vectors, optionals) are not currently supported. Reach out on CDP Discord if you need them.

Instruction discriminators

Discriminators are unique byte sequences that identify instructions within a program:
Program TypeFormatSizeExample
SystemProgram4-byte little-endian u324 bytesTransfer = [2,0,0,0]
SPL Token1-byte enum index1 byteTransfer = 3
Associated TokenBorsh-encoded enum1 byteCreate = 0
Anchor ProgramsSHA256 of "global:instruction_name"8 bytes

IDL configuration

Known program shortcuts

Use predefined names for common programs instead of providing full IDL objects:
  • "SystemProgram" — Native Solana system program
  • "TokenProgram" — SPL Token program
  • "AssociatedTokenProgram" — Associated Token Account program

Custom IDL objects

For custom programs, provide IDL objects with:
  • address — The program’s public key
  • instructions — Array of instruction definitions, each with name, discriminator, and args

Conditions

Evaluation logic

  • Multiple conditions in a solData criterion are evaluated with OR logic — any matching condition passes
  • Parameters within a condition are evaluated with AND logic — all must match

Condition structure

Each condition includes:
  • instruction — Name matching an instruction in one of the provided IDLs
  • params (optional) — Array of parameter validations, each with name, operator (==, <=, >=, <, >, !=, in, not in), and value or values

Examples

Using known program shortcuts

import { CdpClient } from "@coinbase/cdp-sdk";
import "dotenv/config";

const cdp = new CdpClient();

const policy = await cdp.policies.createPolicy({
  policy: {
    scope: "account",
    description: "solData policy using known IDLs",
    rules: [
      {
        action: "accept",
        operation: "signSolTransaction",
        criteria: [
          {
            type: "solData",
            idls: ["SystemProgram", "TokenProgram", "AssociatedTokenProgram"],
            conditions: [
              {
                instruction: "transfer",
                params: [{ name: "lamports", operator: "<=", value: "1000000" }],
              },
              {
                instruction: "transfer_checked",
                params: [
                  { name: "amount", operator: "<=", value: "100000" },
                  { name: "decimals", operator: "==", value: "6" },
                ],
              },
              { instruction: "create" },
            ],
          },
        ],
      },
    ],
  },
});

console.log("Created solData policy:", policy.id);

const account = await cdp.solana.getOrCreateAccount({ name: "MyAccount" });
await cdp.solana.updateAccount({
  address: account.address,
  update: { accountPolicy: policy.id },
});

Using custom IDL objects

import { CdpClient } from "@coinbase/cdp-sdk";

const cdp = new CdpClient();

const policy = await cdp.policies.createPolicy({
  policy: {
    scope: "account",
    description: "solData policy with custom IDLs",
    rules: [
      {
        action: "accept",
        operation: "signSolTransaction",
        criteria: [
          {
            type: "solData",
            idls: [
              {
                address: "11111111111111111111111111111111",
                instructions: [
                  {
                    name: "transfer",
                    discriminator: [163, 52, 200, 231, 140, 3, 69, 186],
                    args: [{ name: "lamports", type: "u64" }],
                  },
                ],
              },
              {
                address: "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA",
                instructions: [
                  {
                    name: "transfer_checked",
                    discriminator: [119, 250, 202, 24, 253, 135, 244, 121],
                    args: [
                      { name: "amount", type: "u64" },
                      { name: "decimals", type: "u8" },
                    ],
                  },
                ],
              },
            ],
            conditions: [
              {
                instruction: "transfer",
                params: [{ name: "lamports", operator: "<=", value: "1000000" }],
              },
              {
                instruction: "transfer_checked",
                params: [
                  { name: "amount", operator: "<=", value: "100000" },
                  { name: "decimals", operator: "==", value: "6" },
                ],
              },
            ],
          },
        ],
      },
    ],
  },
});

console.log("Created custom IDL solData policy:", policy.id);
import { Keypair, PublicKey, TransactionInstruction } from "@solana/web3.js";
import { ASSOCIATED_TOKEN_PROGRAM_ID, TOKEN_PROGRAM_ID } from "@solana/spl-token";

function createAnchorSystemTransferInstruction(amount: bigint): TransactionInstruction {
  const testAccount = Keypair.generate().publicKey;
  const data = Buffer.concat([
    Buffer.from([163, 52, 200, 231, 140, 3, 69, 186]),
    (() => { const b = Buffer.alloc(8); b.writeBigUInt64LE(amount); return b; })(),
  ]);
  return new TransactionInstruction({
    keys: [
      { pubkey: testAccount, isSigner: true, isWritable: true },
      { pubkey: testAccount, isSigner: false, isWritable: true },
    ],
    programId: new PublicKey("11111111111111111111111111111111"),
    data,
  });
}

function createAnchorSPLTransferCheckedInstruction(amount: number, decimals: number): TransactionInstruction {
  const testAccount = Keypair.generate().publicKey;
  const amountBuf = Buffer.alloc(8); amountBuf.writeBigUInt64LE(BigInt(amount));
  const decimalsBuf = Buffer.alloc(1); decimalsBuf.writeUInt8(decimals);
  const data = Buffer.concat([Buffer.from([119, 250, 202, 24, 253, 135, 244, 121]), amountBuf, decimalsBuf]);
  return new TransactionInstruction({
    keys: [
      { pubkey: testAccount, isSigner: false, isWritable: true },
      { pubkey: testAccount, isSigner: false, isWritable: false },
      { pubkey: testAccount, isSigner: false, isWritable: true },
      { pubkey: testAccount, isSigner: true, isWritable: false },
    ],
    programId: TOKEN_PROGRAM_ID,
    data,
  });
}

function createAnchorAssociatedTokenAccountCreateInstruction(): TransactionInstruction {
  const testAccount = Keypair.generate().publicKey;
  return new TransactionInstruction({
    keys: Array(6).fill({ pubkey: testAccount, isSigner: false, isWritable: false }),
    programId: ASSOCIATED_TOKEN_PROGRAM_ID,
    data: Buffer.from([24, 30, 200, 40, 5, 28, 7, 119]),
  });
}
For TypeScript projects using custom Anchor programs, the @coral-xyz/anchor SDK provides type-safe instruction builders and IDL utilities that simplify constructing properly formatted transactions.

Ecosystem program examples

The solData criterion works with any Solana program. Common use cases by category:
CategoryPrograms
DeFi / TradingJupiter (slippage limits), Raydium (liquidity constraints)
StakingJito (validator selection), Marinade (deposit/withdrawal limits)
NFTsMetaplex (mint parameters), Magic Eden (bid validation)

Key considerations

  • Always use Anchor IDL format v0.30+
  • Discriminator bytes must exactly match the program’s instruction identifiers
  • Convert older IDL formats with anchor idl convert before use