Gavel decoder

Decode Gavel instructions and accounts in Rust with carbon-gavel-decoder 2.0.0. Program ID srAMMzfVHVAtgSJc8iH6CfKzuWuUTzLHVCE81QU1rgi.

On this page

carbon-gavel-decoder decodes the instructions and accounts of the Gavel program (srAMMzfVHVAtgSJc8iH6CfKzuWuUTzLHVCE81QU1rgi): 10 instructions, 2 account types. It is generated with Codama from the program's IDL; see decoders for how decoders plug into a pipeline.

Cratecarbon-gavel-decoder 2.0.0
Installcargo add carbon-gavel-decoder@2.0.0
Program IDsrAMMzfVHVAtgSJc8iH6CfKzuWuUTzLHVCE81QU1rgi (carbon_gavel_decoder::PROGRAM_ID)
CategoryDEX & AMM
Decodercarbon_gavel_decoder::GavelDecoder
Instruction enuminstructions::GavelInstruction
Account enumaccounts::GavelAccount
Featuresserde, postgres, graphql (none enabled by default)
API docsdocs.rs/carbon-gavel-decoder/2.0.0
Sourcedecoders/gavel-decoder

Other DEX and AMM decoders: BonkSwap, FluxBeam, Heaven, Jupiter Limit Order, Jupiter Limit Order v2, Kamino Limit Order, Lifinity AMM v2, Meteora DAMM v2, Meteora DLMM, Meteora Pools, OpenBook v2, Orca Whirlpools, PancakeSwap, Phoenix v1, PumpSwap, Raydium AMM v4, Raydium CLMM, Raydium CPMM, Raydium Stable Swap, Stabble Stable Swap, Stabble Weighted Swap. To decode several in one pipeline, see dEX and AMM decoders.

The serde feature derives Serialize/Deserialize on every type, postgres adds tables and processors for Postgres, and graphql adds a schema for the GraphQL server.

Usage#

This program crawls recent Gavel transactions from the public RPC and prints every decoded Swap instruction. Add the dependencies:

Terminal
cargo add carbon-core@2.0.0 carbon-gavel-decoder@2.0.0 carbon-rpc-transaction-crawler-datasource@2.0.0 carbon-log-metrics@2.0.0 env_logger tokio --features tokio/full
src/main.rs
use {
    carbon_core::{
        error::CarbonResult, instruction::InstructionProcessorInputType, pipeline::Pipeline,
        processor::Processor,
    },
    carbon_log_metrics::LogMetrics,
    carbon_gavel_decoder::{instructions::GavelInstruction, GavelDecoder, PROGRAM_ID},
    carbon_rpc_transaction_crawler_datasource::{ConnectionConfig, Filters, RpcTransactionCrawler},
    std::sync::Arc,
};

#[tokio::main]
async fn main() -> CarbonResult<()> {
    env_logger::init();

    // Fetches the program's recent transactions over JSON-RPC, newest first.
    let datasource = RpcTransactionCrawler::new(
        "https://api.mainnet-beta.solana.com".to_string(),
        PROGRAM_ID,
        ConnectionConfig::default(),
        Filters::new(None, None, None),
        None,
    );

    Pipeline::builder()
        .datasource(datasource)
        .metrics(Arc::new(LogMetrics::new()))
        .instruction(GavelDecoder, InstructionLogger)
        .build()?
        .run()
        .await
}

struct InstructionLogger;

impl Processor<InstructionProcessorInputType<'_, GavelInstruction>> for InstructionLogger {
    async fn process(
        &mut self,
        input: &InstructionProcessorInputType<'_, GavelInstruction>,
    ) -> CarbonResult<()> {
        let signature = input.metadata.transaction_metadata.signature;
        if let GavelInstruction::Swap { data, accounts, .. } = input.decoded_instruction {
            println!("swap {signature}: {data:?} plasma_program={}", accounts.plasma_program);
        }
        Ok(())
    }
}
Terminal
RUST_LOG=info cargo run

Each Swap instruction prints one line with the transaction signature and the decoded Swap data. The public endpoint rate-limits requests, so the first lines can take a while; use your own RPC URL for anything beyond a test. See stream with RPC for the crawler options.

Decode accounts#

The transaction crawler emits transactions only. To decode accounts, use a datasource that emits account updates. This program subscribes to the program's accounts with programSubscribe on the public WebSocket endpoint and prints every decoded LpPositionAccount account as it changes. Add the datasource and the Solana RPC types it takes:

Terminal
cargo add carbon-rpc-program-subscribe-datasource@2.0.0 solana-client@4.2.2
src/main.rs
use {
    carbon_core::{
        account::AccountProcessorInputType, error::CarbonResult, pipeline::Pipeline,
        processor::Processor,
    },
    carbon_log_metrics::LogMetrics,
    carbon_gavel_decoder::{accounts::GavelAccount, GavelDecoder, PROGRAM_ID},
    carbon_rpc_program_subscribe_datasource::{Filters, RpcProgramSubscribe},
    solana_client::rpc_config::{RpcAccountInfoConfig, RpcProgramAccountsConfig, UiAccountEncoding},
    std::sync::Arc,
};

#[tokio::main]
async fn main() -> CarbonResult<()> {
    env_logger::init();

    // Streams every change to an account owned by the program (programSubscribe).
    let config = RpcProgramAccountsConfig {
        account_config: RpcAccountInfoConfig {
            encoding: Some(UiAccountEncoding::Base64),
            ..Default::default()
        },
        ..Default::default()
    };
    let datasource = RpcProgramSubscribe::new(
        "wss://api.mainnet-beta.solana.com".to_string(),
        Filters::new(PROGRAM_ID, Some(config)),
    );

    Pipeline::builder()
        .datasource(datasource)
        .metrics(Arc::new(LogMetrics::new()))
        .account(GavelDecoder, AccountLogger)
        .build()?
        .run()
        .await
}

struct AccountLogger;

impl Processor<AccountProcessorInputType<'_, GavelAccount>> for AccountLogger {
    async fn process(
        &mut self,
        input: &AccountProcessorInputType<'_, GavelAccount>,
    ) -> CarbonResult<()> {
        if let GavelAccount::LpPositionAccount(lp_position_account) = &input.decoded_account.data {
            println!("lp_position_account {}: {lp_position_account:?}", input.metadata.pubkey);
        }
        Ok(())
    }
}
Terminal
RUST_LOG=info cargo run

Each update to a LpPositionAccount account prints its address and decoded fields; the program runs until you stop it. Cargo resolves solana-client to 4.2.2, the exact version the datasource pins, so both use the same RpcProgramAccountsConfig type. To load every existing account once instead of streaming changes, see load account state.

Instructions#

Variants of GavelInstruction. Each is GavelInstruction::<Variant> { program_id, data, accounts }, where data and accounts are the types listed under the variant, exported from carbon_gavel_decoder::instructions. Discriminators are the leading bytes of the instruction data, in hex.

How an instruction decodes. The decoder returns a variant only when all of these hold; otherwise the instruction is skipped and no processor is called:

  1. The instruction's program ID is srAMMzfVHVAtgSJc8iH6CfKzuWuUTzLHVCE81QU1rgi.
  2. The data starts with the variant's discriminator, and the rest deserializes into its data type.
  3. The instruction has at least as many accounts as the variant requires (the "Required accounts" count under each variant).

Accounts. They are matched by position, in the order listed. An account marked optional is None only when the instruction ends before it; Anchor programs pass the program ID as a placeholder for an omitted optional account, so check for Some(PROGRAM_ID) too. Accounts after the listed ones are in accounts.remaining as AccountMetas. The decoder doesn't record whether an account signed or was writable: read that from input.raw_instruction.accounts[i].is_signer and .is_writable, which follow the same order. It doesn't check signer, writable, owner or PDA constraints either; the program enforced those when the transaction executed, so a decoded instruction from a successful transaction already satisfied them.

AddLiquidity#

Discriminator 01 · data AddLiquidity · accounts AddLiquidityInstructionAccounts.

FieldType
paramsAddLiquidityIxParams

Required accounts: 10; extras go to remaining.

Fields of AddLiquidityInstructionAccounts, in account order:

#FieldType
0plasma_programPubkey
1log_authorityPubkey
2poolPubkey
3traderPubkey
4lp_positionPubkey
5base_accountPubkey
6quote_accountPubkey
7base_vaultPubkey
8quote_vaultPubkey
9token_programPubkey
10…remainingVec<AccountMeta>

InitializeLpPosition#

Discriminator 05 · data InitializeLpPosition · accounts InitializeLpPositionInstructionAccounts.

No data fields.

Required accounts: 7; extras go to remaining.

Fields of InitializeLpPositionInstructionAccounts, in account order:

#FieldType
0plasma_programPubkey
1log_authorityPubkey
2poolPubkey
3payerPubkey
4lp_position_ownerPubkey
5lp_positionPubkey
6system_programPubkey
7…remainingVec<AccountMeta>

InitializePool#

Discriminator 06 · data InitializePool · accounts InitializePoolInstructionAccounts.

FieldType
paramsInitializePoolIxParams

Required accounts: 10; extras go to remaining.

Fields of InitializePoolInstructionAccounts, in account order:

#FieldType
0plasma_programPubkey
1log_authorityPubkey
2poolPubkey
3pool_creatorPubkey
4base_mintPubkey
5quote_mintPubkey
6base_vaultPubkey
7quote_vaultPubkey
8system_programPubkey
9token_programPubkey
10…remainingVec<AccountMeta>

Log#

Discriminator 08 · data Log · accounts LogInstructionAccounts.

No data fields.

Required accounts: 1; extras go to remaining.

Fields of LogInstructionAccounts, in account order:

#FieldType
0log_authorityPubkey
1…remainingVec<AccountMeta>

RemoveLiquidity#

Discriminator 02 · data RemoveLiquidity · accounts RemoveLiquidityInstructionAccounts.

Required accounts: 10; extras go to remaining.

Fields of RemoveLiquidityInstructionAccounts, in account order:

#FieldType
0plasma_programPubkey
1log_authorityPubkey
2poolPubkey
3traderPubkey
4lp_positionPubkey
5base_accountPubkey
6quote_accountPubkey
7base_vaultPubkey
8quote_vaultPubkey
9token_programPubkey
10…remainingVec<AccountMeta>

RenounceLiquidity#

Discriminator 03 · data RenounceLiquidity · accounts RenounceLiquidityInstructionAccounts.

Required accounts: 5; extras go to remaining.

Fields of RenounceLiquidityInstructionAccounts, in account order:

#FieldType
0plasma_programPubkey
1log_authorityPubkey
2poolPubkey
3traderPubkey
4lp_positionPubkey
5…remainingVec<AccountMeta>

Swap#

Discriminator 00 · data Swap · accounts SwapInstructionAccounts.

FieldType
paramsSwapIxParams

Required accounts: 9; extras go to remaining.

Fields of SwapInstructionAccounts, in account order:

#FieldType
0plasma_programPubkey
1log_authorityPubkey
2poolPubkey
3traderPubkey
4base_accountPubkey
5quote_accountPubkey
6base_vaultPubkey
7quote_vaultPubkey
8token_programPubkey
9…remainingVec<AccountMeta>

TransferLiquidity#

Discriminator 09 · data TransferLiquidity · accounts TransferLiquidityInstructionAccounts.

No data fields.

Required accounts: 6; extras go to remaining.

Fields of TransferLiquidityInstructionAccounts, in account order:

#FieldType
0plasma_programPubkey
1log_authorityPubkey
2poolPubkey
3traderPubkey
4src_lp_positionPubkey
5dst_lp_positionPubkey
6…remainingVec<AccountMeta>

WithdrawLpFees#

Discriminator 04 · data WithdrawLpFees · accounts WithdrawLpFeesInstructionAccounts.

No data fields.

Required accounts: 9; extras go to remaining.

Fields of WithdrawLpFeesInstructionAccounts, in account order:

#FieldType
0plasma_programPubkey
1log_authorityPubkey
2poolPubkey
3traderPubkey
4lp_position_ownerPubkey
5lp_positionPubkey
6quote_accountPubkey
7quote_vaultPubkey
8token_programPubkey
9…remainingVec<AccountMeta>

WithdrawProtocolFees#

Discriminator 07 · data WithdrawProtocolFees · accounts WithdrawProtocolFeesInstructionAccounts.

No data fields.

Required accounts: 7; extras go to remaining.

Fields of WithdrawProtocolFeesInstructionAccounts, in account order:

#FieldType
0plasma_programPubkey
1log_authorityPubkey
2poolPubkey
3protocol_fee_recipientPubkey
4quote_accountPubkey
5quote_vaultPubkey
6token_programPubkey
7…remainingVec<AccountMeta>

Accounts#

Variants of GavelAccount. Each wraps a boxed struct from carbon_gavel_decoder::accounts::<module>. decode_account only considers accounts owned by PROGRAM_ID and returns the first variant that matches.

LpPositionAccount#

No discriminator (matched by Borsh layout) · accounts::lp_position_account::LpPositionAccount.

FieldType
authorityPubkey
poolPubkey
statusu64
lp_positionLpPosition

PoolAccount#

No discriminator (matched by Borsh layout) · accounts::pool_account::PoolAccount.

FieldType
pool_headerPoolHeader
ammAmm

Types#

Types used by the instructions, accounts and events above, exported from carbon_gavel_decoder::types.

AddLiquidityEvent#

Struct types::AddLiquidityEvent.

FieldType
pool_total_lp_sharesu64
pool_total_base_liquidityu64
pool_total_quote_liquitidyu64
snapshot_base_liquidityu64
snapshot_quote_liquidityu64
user_lp_shares_receivedu64
user_lp_shares_availableu64
user_lp_shares_lockedu64
user_lp_shares_unlocked_for_withdrawalu64
user_base_depositedu64
user_quote_depositedu64
user_total_withdrawable_baseu64
user_total_withdrawable_quoteu64

AddLiquidityIxParams#

Struct types::AddLiquidityIxParams.

FieldType
desired_base_amount_inu64
desired_quote_amount_inu64
initial_lp_sharesOption<u64>

Amm#

Struct types::Amm.

FieldType
fee_in_bpsu32
protocol_allocation_in_pctu32
lp_vesting_windowu64
reward_factoru128
total_lp_sharesu64
slot_snapshotu64
base_reserves_snapshotu64
quote_reserves_snapshotu64
base_reservesu64
quote_reservesu64
cumulative_quote_lp_feesu64
cumulative_quote_protocol_feesu64

InitializeLpPositionEvent#

Struct types::InitializeLpPositionEvent.

FieldType
ownerPubkey

InitializePoolEvent#

Struct types::InitializePoolEvent.

FieldType
lp_fee_in_bpsu64
protocol_fee_in_pctu64
fee_recipient_params[ProtocolFeeRecipientParams; 3]

InitializePoolIxParams#

Struct types::InitializePoolIxParams.

FieldType
lp_fee_in_bpsu64
protocol_lp_fee_allocation_in_pctu64
fee_recipients_params[ProtocolFeeRecipientParams; 3]
num_slots_to_vest_lp_sharesOption<u64>

LpPosition#

Struct types::LpPosition.

FieldType
reward_factor_snapshotu128
lp_sharesu64
withdrawable_lp_sharesu64
uncollected_feesu64
collected_feesu64
pending_shares_to_vestPendingSharesToVest

PendingSharesToVest#

Struct types::PendingSharesToVest.

FieldType
deposit_slotu64
lp_shares_to_vestu64

PlasmaEvent#

Enum types::PlasmaEvent.

VariantFields
Swapheader: PlasmaEventHeader, event: SwapEvent
AddLiquidityheader: PlasmaEventHeader, event: AddLiquidityEvent
RemoveLiquidityheader: PlasmaEventHeader, event: RemoveLiquidityEvent
RenounceLiquidityheader: PlasmaEventHeader, event: RenounceLiquidityEvent
WithdrawLpFeesheader: PlasmaEventHeader, event: WithdrawLpFeesEvent
InitializeLpPositionheader: PlasmaEventHeader, event: InitializeLpPositionEvent
InitializePoolheader: PlasmaEventHeader, event: InitializePoolEvent
WithdrawProtocolFeesheader: PlasmaEventHeader, event: WithdrawProtocolFeesEvent

PlasmaEventHeader#

Struct types::PlasmaEventHeader.

FieldType
sequence_numberu64
slotu64
timestampi64
poolPubkey
signerPubkey
base_decimalsu8
quote_decimalsu8

PoolHeader#

Struct types::PoolHeader.

FieldType
sequence_numberu64
base_paramsTokenParams
quote_paramsTokenParams
fee_recipientsProtocolFeeRecipients
swap_sequence_numberu64
padding[u64; 12]

ProtocolFeeRecipient#

Struct types::ProtocolFeeRecipient.

FieldType
recipientPubkey
sharesu64
total_accumulated_quote_feesu64
collected_quote_feesu64

ProtocolFeeRecipientParams#

Struct types::ProtocolFeeRecipientParams.

FieldType
recipientPubkey
sharesu64

ProtocolFeeRecipients#

Struct types::ProtocolFeeRecipients.

FieldType
recipients[ProtocolFeeRecipient; 3]
padding[u64; 12]

RemoveLiquidityEvent#

Struct types::RemoveLiquidityEvent.

FieldType
pool_total_lp_sharesu64
pool_total_base_liquidityu64
pool_total_quote_liquitidyu64
snapshot_base_liquidityu64
snapshot_quote_liquidityu64
user_lp_shares_burnedu64
user_lp_shares_availableu64
user_lp_shares_lockedu64
user_lp_shares_unlocked_for_withdrawalu64
user_base_withdrawnu64
user_quote_withdrawnu64
user_total_withdrawable_baseu64
user_total_withdrawable_quoteu64

RemoveLiquidityIxParams#

Struct types::RemoveLiquidityIxParams.

FieldType
lp_sharesu64

RenounceLiquidityEvent#

Struct types::RenounceLiquidityEvent.

FieldType
allow_fee_withdrawalbool

RenounceLiquidityIxParams#

Struct types::RenounceLiquidityIxParams.

FieldType
allow_fee_withdrawalbool

Side#

Enum types::Side.

Variant
Buy
Sell

SwapEvent#

Struct types::SwapEvent.

FieldType
swap_sequence_numberu64
pre_base_liquidityu64
pre_quote_liquidityu64
post_base_liquidityu64
post_quote_liquidityu64
snapshot_base_liquidityu64
snapshot_quote_liquidityu64
swap_resultSwapResult

SwapIxParams#

Struct types::SwapIxParams.

FieldType
sideSide
swap_typeSwapType

SwapResult#

Struct types::SwapResult.

FieldType
sideSide
base_matchedu64
quote_matchedu64
base_matched_as_limit_orderu64
quote_matched_as_limit_orderu64
base_matched_as_swapu64
quote_matched_as_swapu64
fee_in_quoteu64

SwapType#

Enum types::SwapType.

VariantFields
ExactInamount_in: u64, min_amount_out: u64
ExactOutamount_out: u64, max_amount_in: u64

TokenParams#

Struct types::TokenParams.

FieldType
decimalsu32
vault_bumpu32
mint_keyPubkey
vault_keyPubkey

WithdrawLpFeesEvent#

Struct types::WithdrawLpFeesEvent.

FieldType
fees_withdrawnu64

WithdrawProtocolFeesEvent#

Struct types::WithdrawProtocolFeesEvent.

FieldType
protocol_fee_recipientPubkey
fees_withdrawnu64

Generated from the crate’s source at Carbon v2.0.0, so it always matches the published code. Spotted a problem? Report it; edits to this page itself are overwritten on the next release.

Your endpoints

Code samples use these instead of the placeholders, so you can copy and run them as they are. They’re stored only in this browser and never sent anywhere.