Files
khadhroony-bobobot/kb_lib/src/dex/pump_fees.rs

2497 lines
92 KiB
Rust

// file: kb_lib/src/dex/pump_fees.rs
//! Pump Fees fee/config/accounting transaction decoder.
const PUMP_FEES_ANCHOR_SELF_CPI_LOG_DISCRIMINATOR: [u8; 8] = [228, 69, 165, 46, 81, 203, 154, 29];
const PUMP_FEES_CLAIM_SOCIAL_FEE_PDA_DISCRIMINATOR: [u8; 8] =
[225, 21, 251, 133, 161, 30, 199, 226];
const PUMP_FEES_CLAIM_SOCIAL_FEE_PDA_V2_DISCRIMINATOR: [u8; 8] =
[17, 77, 240, 134, 58, 188, 53, 149];
const PUMP_FEES_CRANK_DONATION_FEE_PDA_DISCRIMINATOR: [u8; 8] =
[220, 10, 189, 167, 169, 17, 25, 69];
const PUMP_FEES_CREATE_DONATION_FEE_PDA_DISCRIMINATOR: [u8; 8] =
[244, 139, 16, 88, 14, 255, 122, 26];
const PUMP_FEES_CREATE_FEE_SHARING_CONFIG_DISCRIMINATOR: [u8; 8] =
[195, 78, 86, 76, 111, 52, 251, 213];
const PUMP_FEES_CREATE_SOCIAL_FEE_PDA_DISCRIMINATOR: [u8; 8] =
[144, 224, 59, 211, 78, 248, 202, 220];
const PUMP_FEES_EXTEND_FEE_CONFIG_DISCRIMINATOR: [u8; 8] = [68, 179, 244, 90, 173, 56, 17, 217];
const PUMP_FEES_GET_FEES_DISCRIMINATOR: [u8; 8] = [231, 37, 126, 85, 207, 91, 63, 52];
const PUMP_FEES_INITIALIZE_BUYBACK_DISCRIMINATOR: [u8; 8] = [250, 129, 236, 160, 227, 36, 103, 134];
const PUMP_FEES_INITIALIZE_FEE_CONFIG_DISCRIMINATOR: [u8; 8] = [62, 162, 20, 133, 121, 65, 145, 27];
const PUMP_FEES_INITIALIZE_FEE_PROGRAM_GLOBAL_DISCRIMINATOR: [u8; 8] =
[35, 215, 130, 84, 233, 56, 124, 167];
const PUMP_FEES_RESET_FEE_SHARING_CONFIG_DISCRIMINATOR: [u8; 8] =
[10, 2, 182, 95, 16, 127, 129, 186];
const PUMP_FEES_RESET_FEE_SHARING_CONFIG_V2_DISCRIMINATOR: [u8; 8] =
[169, 245, 17, 209, 94, 91, 248, 128];
const PUMP_FEES_REVOKE_FEE_SHARING_AUTHORITY_DISCRIMINATOR: [u8; 8] =
[18, 233, 158, 39, 185, 207, 58, 104];
const PUMP_FEES_SET_AUTHORITY_DISCRIMINATOR: [u8; 8] = [133, 250, 37, 21, 110, 163, 26, 121];
const PUMP_FEES_SET_CLAIM_RATE_LIMIT_DISCRIMINATOR: [u8; 8] = [185, 211, 159, 174, 212, 49, 88, 4];
const PUMP_FEES_SET_DISABLE_FLAGS_DISCRIMINATOR: [u8; 8] = [194, 217, 112, 35, 114, 222, 51, 190];
const PUMP_FEES_SET_SOCIAL_CLAIM_AUTHORITY_DISCRIMINATOR: [u8; 8] =
[147, 54, 184, 154, 136, 237, 185, 153];
const PUMP_FEES_SWEEP_BUYBACK_DISCRIMINATOR: [u8; 8] = [138, 33, 204, 38, 207, 161, 159, 226];
const PUMP_FEES_TRANSFER_FEE_SHARING_AUTHORITY_DISCRIMINATOR: [u8; 8] =
[202, 10, 75, 200, 164, 34, 210, 96];
const PUMP_FEES_UPDATE_ADMIN_DISCRIMINATOR: [u8; 8] = [161, 176, 40, 213, 60, 184, 179, 228];
const PUMP_FEES_UPDATE_BUYBACK_AUTHORITY_DISCRIMINATOR: [u8; 8] =
[66, 98, 113, 202, 121, 37, 219, 107];
const PUMP_FEES_UPDATE_BUYBACK_CLAIM_RATE_LIMIT_DISCRIMINATOR: [u8; 8] =
[186, 95, 135, 190, 255, 199, 137, 170];
const PUMP_FEES_UPDATE_FEE_CONFIG_DISCRIMINATOR: [u8; 8] = [104, 184, 103, 242, 88, 151, 107, 20];
const PUMP_FEES_UPDATE_FEE_SHARES_DISCRIMINATOR: [u8; 8] = [189, 13, 136, 99, 187, 164, 237, 35];
const PUMP_FEES_UPDATE_FEE_SHARES_V2_DISCRIMINATOR: [u8; 8] = [111, 251, 49, 6, 78, 78, 106, 18];
const PUMP_FEES_UPDATE_STABLE_FEE_CONFIG_DISCRIMINATOR: [u8; 8] =
[107, 169, 100, 179, 134, 155, 146, 221];
const PUMP_FEES_UPSERT_FEE_TIERS_DISCRIMINATOR: [u8; 8] = [227, 23, 150, 12, 77, 86, 94, 4];
const PUMP_FEES_UPSERT_STABLE_FEE_TIERS_DISCRIMINATOR: [u8; 8] =
[181, 160, 162, 252, 74, 76, 224, 221];
const PUMP_FEES_CREATE_FEE_SHARING_CONFIG_EVENT_DISCRIMINATOR: [u8; 8] =
[133, 105, 170, 200, 184, 116, 251, 88];
const PUMP_FEES_DONATION_FEE_PDA_CRANKED_DISCRIMINATOR: [u8; 8] =
[30, 208, 107, 93, 177, 0, 223, 78];
const PUMP_FEES_DONATION_FEE_PDA_CREATED_DISCRIMINATOR: [u8; 8] =
[94, 20, 137, 239, 35, 77, 225, 235];
const PUMP_FEES_EXTEND_FEE_CONFIG_EVENT_DISCRIMINATOR: [u8; 8] =
[226, 203, 224, 35, 153, 10, 88, 51];
const PUMP_FEES_INITIALIZE_FEE_CONFIG_EVENT_DISCRIMINATOR: [u8; 8] =
[89, 138, 244, 230, 10, 56, 226, 126];
const PUMP_FEES_INITIALIZE_FEE_PROGRAM_GLOBAL_EVENT_DISCRIMINATOR: [u8; 8] =
[40, 233, 156, 78, 95, 0, 8, 199];
const PUMP_FEES_RESET_FEE_SHARING_CONFIG_EVENT_DISCRIMINATOR: [u8; 8] =
[203, 204, 151, 226, 120, 55, 214, 243];
const PUMP_FEES_SET_AUTHORITY_EVENT_DISCRIMINATOR: [u8; 8] = [18, 175, 132, 66, 208, 201, 87, 242];
const PUMP_FEES_SET_CLAIM_RATE_LIMIT_EVENT_DISCRIMINATOR: [u8; 8] =
[13, 143, 143, 235, 181, 19, 51, 40];
const PUMP_FEES_SET_DISABLE_FLAGS_EVENT_DISCRIMINATOR: [u8; 8] = [5, 8, 179, 65, 49, 55, 145, 126];
const PUMP_FEES_SET_SOCIAL_CLAIM_AUTHORITY_EVENT_DISCRIMINATOR: [u8; 8] =
[60, 118, 127, 132, 239, 52, 254, 14];
const PUMP_FEES_SOCIAL_FEE_PDA_CLAIMED_DISCRIMINATOR: [u8; 8] =
[50, 18, 193, 65, 237, 210, 234, 236];
const PUMP_FEES_SOCIAL_FEE_PDA_CREATED_DISCRIMINATOR: [u8; 8] =
[183, 183, 218, 147, 24, 124, 137, 169];
const PUMP_FEES_SWEEP_BUYBACK_EVENT_DISCRIMINATOR: [u8; 8] = [43, 56, 42, 214, 153, 57, 166, 137];
const PUMP_FEES_UPDATE_ADMIN_EVENT_DISCRIMINATOR: [u8; 8] = [225, 152, 171, 87, 246, 63, 66, 234];
const PUMP_FEES_UPDATE_FEE_CONFIG_EVENT_DISCRIMINATOR: [u8; 8] =
[90, 23, 65, 35, 62, 244, 188, 208];
const PUMP_FEES_UPDATE_FEE_SHARES_EVENT_DISCRIMINATOR: [u8; 8] =
[21, 186, 196, 184, 91, 228, 225, 203];
const PUMP_FEES_UPDATE_STABLE_FEE_CONFIG_EVENT_DISCRIMINATOR: [u8; 8] =
[94, 5, 43, 237, 103, 147, 232, 245];
const PUMP_FEES_UPSERT_FEE_TIERS_EVENT_DISCRIMINATOR: [u8; 8] =
[171, 89, 169, 187, 122, 186, 33, 204];
const PUMP_FEES_UPSERT_STABLE_FEE_TIERS_EVENT_DISCRIMINATOR: [u8; 8] =
[232, 237, 237, 52, 98, 146, 73, 243];
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
enum PumpFeesBorshFieldKind {
U8,
U64,
I64,
U128,
Bool,
Pubkey,
String,
OptionBool,
OptionPubkey,
Fees,
ConfigStatus,
ShareholderVec,
FeeTierVec,
}
#[derive(Debug, Clone, Copy)]
struct PumpFeesBorshFieldDescriptor {
name: &'static str,
kind: PumpFeesBorshFieldKind,
}
#[derive(Debug, Clone, Copy)]
struct PumpFeesInstructionSpec {
name: &'static str,
fields: &'static [PumpFeesBorshFieldDescriptor],
}
#[derive(Debug, Clone, Copy)]
struct PumpFeesAnchorEventSpec {
name: &'static str,
event_kind: &'static str,
fields: &'static [PumpFeesBorshFieldDescriptor],
}
const PUMP_FEES_INSTRUCTION_CLAIM_SOCIAL_FEE_PDA_FIELDS: &[PumpFeesBorshFieldDescriptor] = &[
PumpFeesBorshFieldDescriptor {
name: "user_id",
kind: PumpFeesBorshFieldKind::String,
},
PumpFeesBorshFieldDescriptor {
name: "platform",
kind: PumpFeesBorshFieldKind::U8,
},
];
const PUMP_FEES_INSTRUCTION_CLAIM_SOCIAL_FEE_PDA_V2_FIELDS: &[PumpFeesBorshFieldDescriptor] = &[
PumpFeesBorshFieldDescriptor {
name: "user_id",
kind: PumpFeesBorshFieldKind::String,
},
PumpFeesBorshFieldDescriptor {
name: "platform",
kind: PumpFeesBorshFieldKind::U8,
},
];
const PUMP_FEES_INSTRUCTION_CRANK_DONATION_FEE_PDA_FIELDS: &[PumpFeesBorshFieldDescriptor] = &[];
const PUMP_FEES_INSTRUCTION_CREATE_DONATION_FEE_PDA_FIELDS: &[PumpFeesBorshFieldDescriptor] = &[];
const PUMP_FEES_INSTRUCTION_CREATE_FEE_SHARING_CONFIG_FIELDS: &[PumpFeesBorshFieldDescriptor] = &[];
const PUMP_FEES_INSTRUCTION_CREATE_SOCIAL_FEE_PDA_FIELDS: &[PumpFeesBorshFieldDescriptor] = &[
PumpFeesBorshFieldDescriptor {
name: "user_id",
kind: PumpFeesBorshFieldKind::String,
},
PumpFeesBorshFieldDescriptor {
name: "platform",
kind: PumpFeesBorshFieldKind::U8,
},
];
const PUMP_FEES_INSTRUCTION_EXTEND_FEE_CONFIG_FIELDS: &[PumpFeesBorshFieldDescriptor] = &[];
const PUMP_FEES_INSTRUCTION_GET_FEES_FIELDS: &[PumpFeesBorshFieldDescriptor] = &[
PumpFeesBorshFieldDescriptor {
name: "is_pump_pool",
kind: PumpFeesBorshFieldKind::Bool,
},
PumpFeesBorshFieldDescriptor {
name: "market_cap_lamports",
kind: PumpFeesBorshFieldKind::U128,
},
PumpFeesBorshFieldDescriptor {
name: "trade_size_lamports",
kind: PumpFeesBorshFieldKind::U64,
},
PumpFeesBorshFieldDescriptor {
name: "is_new_quote_mint",
kind: PumpFeesBorshFieldKind::OptionBool,
},
];
const PUMP_FEES_INSTRUCTION_INITIALIZE_BUYBACK_FIELDS: &[PumpFeesBorshFieldDescriptor] =
&[PumpFeesBorshFieldDescriptor {
name: "index",
kind: PumpFeesBorshFieldKind::U8,
}];
const PUMP_FEES_INSTRUCTION_INITIALIZE_FEE_CONFIG_FIELDS: &[PumpFeesBorshFieldDescriptor] = &[];
const PUMP_FEES_INSTRUCTION_INITIALIZE_FEE_PROGRAM_GLOBAL_FIELDS:
&[PumpFeesBorshFieldDescriptor] = &[
PumpFeesBorshFieldDescriptor {
name: "social_claim_authority",
kind: PumpFeesBorshFieldKind::Pubkey,
},
PumpFeesBorshFieldDescriptor {
name: "disable_flags",
kind: PumpFeesBorshFieldKind::U8,
},
PumpFeesBorshFieldDescriptor {
name: "claim_rate_limit",
kind: PumpFeesBorshFieldKind::U64,
},
];
const PUMP_FEES_INSTRUCTION_RESET_FEE_SHARING_CONFIG_FIELDS: &[PumpFeesBorshFieldDescriptor] = &[];
const PUMP_FEES_INSTRUCTION_RESET_FEE_SHARING_CONFIG_V2_FIELDS: &[PumpFeesBorshFieldDescriptor] =
&[];
const PUMP_FEES_INSTRUCTION_REVOKE_FEE_SHARING_AUTHORITY_FIELDS: &[PumpFeesBorshFieldDescriptor] =
&[];
const PUMP_FEES_INSTRUCTION_SET_AUTHORITY_FIELDS: &[PumpFeesBorshFieldDescriptor] =
&[PumpFeesBorshFieldDescriptor {
name: "new_authority",
kind: PumpFeesBorshFieldKind::Pubkey,
}];
const PUMP_FEES_INSTRUCTION_SET_CLAIM_RATE_LIMIT_FIELDS: &[PumpFeesBorshFieldDescriptor] =
&[PumpFeesBorshFieldDescriptor {
name: "claim_rate_limit",
kind: PumpFeesBorshFieldKind::U64,
}];
const PUMP_FEES_INSTRUCTION_SET_DISABLE_FLAGS_FIELDS: &[PumpFeesBorshFieldDescriptor] =
&[PumpFeesBorshFieldDescriptor {
name: "disable_flags",
kind: PumpFeesBorshFieldKind::U8,
}];
const PUMP_FEES_INSTRUCTION_SET_SOCIAL_CLAIM_AUTHORITY_FIELDS: &[PumpFeesBorshFieldDescriptor] =
&[PumpFeesBorshFieldDescriptor {
name: "social_claim_authority",
kind: PumpFeesBorshFieldKind::Pubkey,
}];
const PUMP_FEES_INSTRUCTION_SWEEP_BUYBACK_FIELDS: &[PumpFeesBorshFieldDescriptor] =
&[PumpFeesBorshFieldDescriptor {
name: "index",
kind: PumpFeesBorshFieldKind::U8,
}];
const PUMP_FEES_INSTRUCTION_TRANSFER_FEE_SHARING_AUTHORITY_FIELDS:
&[PumpFeesBorshFieldDescriptor] = &[];
const PUMP_FEES_INSTRUCTION_UPDATE_ADMIN_FIELDS: &[PumpFeesBorshFieldDescriptor] = &[];
const PUMP_FEES_INSTRUCTION_UPDATE_BUYBACK_AUTHORITY_FIELDS: &[PumpFeesBorshFieldDescriptor] = &[
PumpFeesBorshFieldDescriptor {
name: "index",
kind: PumpFeesBorshFieldKind::U8,
},
PumpFeesBorshFieldDescriptor {
name: "new_authority",
kind: PumpFeesBorshFieldKind::Pubkey,
},
];
const PUMP_FEES_INSTRUCTION_UPDATE_BUYBACK_CLAIM_RATE_LIMIT_FIELDS:
&[PumpFeesBorshFieldDescriptor] = &[
PumpFeesBorshFieldDescriptor {
name: "index",
kind: PumpFeesBorshFieldKind::U8,
},
PumpFeesBorshFieldDescriptor {
name: "claim_rate_limit",
kind: PumpFeesBorshFieldKind::I64,
},
];
const PUMP_FEES_INSTRUCTION_UPDATE_FEE_CONFIG_FIELDS: &[PumpFeesBorshFieldDescriptor] = &[
PumpFeesBorshFieldDescriptor {
name: "fee_tiers",
kind: PumpFeesBorshFieldKind::FeeTierVec,
},
PumpFeesBorshFieldDescriptor {
name: "flat_fees",
kind: PumpFeesBorshFieldKind::Fees,
},
];
const PUMP_FEES_INSTRUCTION_UPDATE_FEE_SHARES_FIELDS: &[PumpFeesBorshFieldDescriptor] =
&[PumpFeesBorshFieldDescriptor {
name: "shareholders",
kind: PumpFeesBorshFieldKind::ShareholderVec,
}];
const PUMP_FEES_INSTRUCTION_UPDATE_FEE_SHARES_V2_FIELDS: &[PumpFeesBorshFieldDescriptor] =
&[PumpFeesBorshFieldDescriptor {
name: "shareholders",
kind: PumpFeesBorshFieldKind::ShareholderVec,
}];
const PUMP_FEES_INSTRUCTION_UPDATE_STABLE_FEE_CONFIG_FIELDS: &[PumpFeesBorshFieldDescriptor] =
&[PumpFeesBorshFieldDescriptor {
name: "fee_tiers",
kind: PumpFeesBorshFieldKind::FeeTierVec,
}];
const PUMP_FEES_INSTRUCTION_UPSERT_FEE_TIERS_FIELDS: &[PumpFeesBorshFieldDescriptor] = &[
PumpFeesBorshFieldDescriptor {
name: "fee_tiers",
kind: PumpFeesBorshFieldKind::FeeTierVec,
},
PumpFeesBorshFieldDescriptor {
name: "offset",
kind: PumpFeesBorshFieldKind::U8,
},
];
const PUMP_FEES_INSTRUCTION_UPSERT_STABLE_FEE_TIERS_FIELDS: &[PumpFeesBorshFieldDescriptor] = &[
PumpFeesBorshFieldDescriptor {
name: "fee_tiers",
kind: PumpFeesBorshFieldKind::FeeTierVec,
},
PumpFeesBorshFieldDescriptor {
name: "offset",
kind: PumpFeesBorshFieldKind::U8,
},
];
const PUMP_FEES_EVENT_CREATE_FEE_SHARING_CONFIG_EVENT_FIELDS: &[PumpFeesBorshFieldDescriptor] = &[
PumpFeesBorshFieldDescriptor {
name: "timestamp",
kind: PumpFeesBorshFieldKind::I64,
},
PumpFeesBorshFieldDescriptor {
name: "mint",
kind: PumpFeesBorshFieldKind::Pubkey,
},
PumpFeesBorshFieldDescriptor {
name: "bonding_curve",
kind: PumpFeesBorshFieldKind::Pubkey,
},
PumpFeesBorshFieldDescriptor {
name: "pool",
kind: PumpFeesBorshFieldKind::OptionPubkey,
},
PumpFeesBorshFieldDescriptor {
name: "sharing_config",
kind: PumpFeesBorshFieldKind::Pubkey,
},
PumpFeesBorshFieldDescriptor {
name: "admin",
kind: PumpFeesBorshFieldKind::Pubkey,
},
PumpFeesBorshFieldDescriptor {
name: "initial_shareholders",
kind: PumpFeesBorshFieldKind::ShareholderVec,
},
PumpFeesBorshFieldDescriptor {
name: "status",
kind: PumpFeesBorshFieldKind::ConfigStatus,
},
];
const PUMP_FEES_EVENT_DONATION_FEE_PDA_CRANKED_FIELDS: &[PumpFeesBorshFieldDescriptor] = &[
PumpFeesBorshFieldDescriptor {
name: "timestamp",
kind: PumpFeesBorshFieldKind::I64,
},
PumpFeesBorshFieldDescriptor {
name: "signer",
kind: PumpFeesBorshFieldKind::Pubkey,
},
PumpFeesBorshFieldDescriptor {
name: "donation_fee_pda",
kind: PumpFeesBorshFieldKind::Pubkey,
},
PumpFeesBorshFieldDescriptor {
name: "config_id",
kind: PumpFeesBorshFieldKind::Pubkey,
},
PumpFeesBorshFieldDescriptor {
name: "base_mint",
kind: PumpFeesBorshFieldKind::Pubkey,
},
PumpFeesBorshFieldDescriptor {
name: "quote_mint",
kind: PumpFeesBorshFieldKind::Pubkey,
},
PumpFeesBorshFieldDescriptor {
name: "creator",
kind: PumpFeesBorshFieldKind::Pubkey,
},
PumpFeesBorshFieldDescriptor {
name: "amount",
kind: PumpFeesBorshFieldKind::U64,
},
];
const PUMP_FEES_EVENT_DONATION_FEE_PDA_CREATED_FIELDS: &[PumpFeesBorshFieldDescriptor] = &[
PumpFeesBorshFieldDescriptor {
name: "timestamp",
kind: PumpFeesBorshFieldKind::I64,
},
PumpFeesBorshFieldDescriptor {
name: "created_by",
kind: PumpFeesBorshFieldKind::Pubkey,
},
PumpFeesBorshFieldDescriptor {
name: "donation_fee_pda",
kind: PumpFeesBorshFieldKind::Pubkey,
},
PumpFeesBorshFieldDescriptor {
name: "config_id",
kind: PumpFeesBorshFieldKind::Pubkey,
},
PumpFeesBorshFieldDescriptor {
name: "base_mint",
kind: PumpFeesBorshFieldKind::Pubkey,
},
PumpFeesBorshFieldDescriptor {
name: "quote_mint",
kind: PumpFeesBorshFieldKind::Pubkey,
},
PumpFeesBorshFieldDescriptor {
name: "creator",
kind: PumpFeesBorshFieldKind::Pubkey,
},
];
const PUMP_FEES_EVENT_EXTEND_FEE_CONFIG_EVENT_FIELDS: &[PumpFeesBorshFieldDescriptor] = &[
PumpFeesBorshFieldDescriptor {
name: "fee_config",
kind: PumpFeesBorshFieldKind::Pubkey,
},
PumpFeesBorshFieldDescriptor {
name: "user",
kind: PumpFeesBorshFieldKind::Pubkey,
},
PumpFeesBorshFieldDescriptor {
name: "current_size",
kind: PumpFeesBorshFieldKind::U64,
},
PumpFeesBorshFieldDescriptor {
name: "new_size",
kind: PumpFeesBorshFieldKind::U64,
},
PumpFeesBorshFieldDescriptor {
name: "timestamp",
kind: PumpFeesBorshFieldKind::I64,
},
];
const PUMP_FEES_EVENT_INITIALIZE_FEE_CONFIG_EVENT_FIELDS: &[PumpFeesBorshFieldDescriptor] = &[
PumpFeesBorshFieldDescriptor {
name: "timestamp",
kind: PumpFeesBorshFieldKind::I64,
},
PumpFeesBorshFieldDescriptor {
name: "admin",
kind: PumpFeesBorshFieldKind::Pubkey,
},
PumpFeesBorshFieldDescriptor {
name: "fee_config",
kind: PumpFeesBorshFieldKind::Pubkey,
},
];
const PUMP_FEES_EVENT_INITIALIZE_FEE_PROGRAM_GLOBAL_EVENT_FIELDS:
&[PumpFeesBorshFieldDescriptor] = &[
PumpFeesBorshFieldDescriptor {
name: "timestamp",
kind: PumpFeesBorshFieldKind::I64,
},
PumpFeesBorshFieldDescriptor {
name: "authority",
kind: PumpFeesBorshFieldKind::Pubkey,
},
PumpFeesBorshFieldDescriptor {
name: "social_claim_authority",
kind: PumpFeesBorshFieldKind::Pubkey,
},
PumpFeesBorshFieldDescriptor {
name: "disable_flags",
kind: PumpFeesBorshFieldKind::U8,
},
PumpFeesBorshFieldDescriptor {
name: "claim_rate_limit",
kind: PumpFeesBorshFieldKind::U64,
},
];
const PUMP_FEES_EVENT_RESET_FEE_SHARING_CONFIG_EVENT_FIELDS: &[PumpFeesBorshFieldDescriptor] = &[
PumpFeesBorshFieldDescriptor {
name: "timestamp",
kind: PumpFeesBorshFieldKind::I64,
},
PumpFeesBorshFieldDescriptor {
name: "mint",
kind: PumpFeesBorshFieldKind::Pubkey,
},
PumpFeesBorshFieldDescriptor {
name: "sharing_config",
kind: PumpFeesBorshFieldKind::Pubkey,
},
PumpFeesBorshFieldDescriptor {
name: "old_admin",
kind: PumpFeesBorshFieldKind::Pubkey,
},
PumpFeesBorshFieldDescriptor {
name: "old_shareholders",
kind: PumpFeesBorshFieldKind::ShareholderVec,
},
PumpFeesBorshFieldDescriptor {
name: "new_admin",
kind: PumpFeesBorshFieldKind::Pubkey,
},
PumpFeesBorshFieldDescriptor {
name: "new_shareholders",
kind: PumpFeesBorshFieldKind::ShareholderVec,
},
PumpFeesBorshFieldDescriptor {
name: "old_version",
kind: PumpFeesBorshFieldKind::U8,
},
PumpFeesBorshFieldDescriptor {
name: "new_version",
kind: PumpFeesBorshFieldKind::U8,
},
];
const PUMP_FEES_EVENT_SET_AUTHORITY_EVENT_FIELDS: &[PumpFeesBorshFieldDescriptor] = &[
PumpFeesBorshFieldDescriptor {
name: "timestamp",
kind: PumpFeesBorshFieldKind::I64,
},
PumpFeesBorshFieldDescriptor {
name: "old_authority",
kind: PumpFeesBorshFieldKind::Pubkey,
},
PumpFeesBorshFieldDescriptor {
name: "new_authority",
kind: PumpFeesBorshFieldKind::Pubkey,
},
];
const PUMP_FEES_EVENT_SET_CLAIM_RATE_LIMIT_EVENT_FIELDS: &[PumpFeesBorshFieldDescriptor] = &[
PumpFeesBorshFieldDescriptor {
name: "timestamp",
kind: PumpFeesBorshFieldKind::I64,
},
PumpFeesBorshFieldDescriptor {
name: "claim_rate_limit",
kind: PumpFeesBorshFieldKind::U64,
},
];
const PUMP_FEES_EVENT_SET_DISABLE_FLAGS_EVENT_FIELDS: &[PumpFeesBorshFieldDescriptor] = &[
PumpFeesBorshFieldDescriptor {
name: "timestamp",
kind: PumpFeesBorshFieldKind::I64,
},
PumpFeesBorshFieldDescriptor {
name: "disable_flags",
kind: PumpFeesBorshFieldKind::U8,
},
];
const PUMP_FEES_EVENT_SET_SOCIAL_CLAIM_AUTHORITY_EVENT_FIELDS: &[PumpFeesBorshFieldDescriptor] = &[
PumpFeesBorshFieldDescriptor {
name: "timestamp",
kind: PumpFeesBorshFieldKind::I64,
},
PumpFeesBorshFieldDescriptor {
name: "social_claim_authority",
kind: PumpFeesBorshFieldKind::Pubkey,
},
];
const PUMP_FEES_EVENT_SOCIAL_FEE_PDA_CLAIMED_FIELDS: &[PumpFeesBorshFieldDescriptor] = &[
PumpFeesBorshFieldDescriptor {
name: "timestamp",
kind: PumpFeesBorshFieldKind::I64,
},
PumpFeesBorshFieldDescriptor {
name: "user_id",
kind: PumpFeesBorshFieldKind::String,
},
PumpFeesBorshFieldDescriptor {
name: "platform",
kind: PumpFeesBorshFieldKind::U8,
},
PumpFeesBorshFieldDescriptor {
name: "social_fee_pda",
kind: PumpFeesBorshFieldKind::Pubkey,
},
PumpFeesBorshFieldDescriptor {
name: "recipient",
kind: PumpFeesBorshFieldKind::Pubkey,
},
PumpFeesBorshFieldDescriptor {
name: "social_claim_authority",
kind: PumpFeesBorshFieldKind::Pubkey,
},
PumpFeesBorshFieldDescriptor {
name: "amount_claimed",
kind: PumpFeesBorshFieldKind::U64,
},
PumpFeesBorshFieldDescriptor {
name: "claimable_before",
kind: PumpFeesBorshFieldKind::U64,
},
PumpFeesBorshFieldDescriptor {
name: "lifetime_claimed",
kind: PumpFeesBorshFieldKind::U64,
},
PumpFeesBorshFieldDescriptor {
name: "recipient_balance_before",
kind: PumpFeesBorshFieldKind::U64,
},
PumpFeesBorshFieldDescriptor {
name: "recipient_balance_after",
kind: PumpFeesBorshFieldKind::U64,
},
PumpFeesBorshFieldDescriptor {
name: "quote_mint",
kind: PumpFeesBorshFieldKind::Pubkey,
},
];
const PUMP_FEES_EVENT_SOCIAL_FEE_PDA_CREATED_FIELDS: &[PumpFeesBorshFieldDescriptor] = &[
PumpFeesBorshFieldDescriptor {
name: "timestamp",
kind: PumpFeesBorshFieldKind::I64,
},
PumpFeesBorshFieldDescriptor {
name: "user_id",
kind: PumpFeesBorshFieldKind::String,
},
PumpFeesBorshFieldDescriptor {
name: "platform",
kind: PumpFeesBorshFieldKind::U8,
},
PumpFeesBorshFieldDescriptor {
name: "social_fee_pda",
kind: PumpFeesBorshFieldKind::Pubkey,
},
PumpFeesBorshFieldDescriptor {
name: "created_by",
kind: PumpFeesBorshFieldKind::Pubkey,
},
];
const PUMP_FEES_EVENT_SWEEP_BUYBACK_EVENT_FIELDS: &[PumpFeesBorshFieldDescriptor] = &[
PumpFeesBorshFieldDescriptor {
name: "index",
kind: PumpFeesBorshFieldKind::U8,
},
PumpFeesBorshFieldDescriptor {
name: "sol_amount",
kind: PumpFeesBorshFieldKind::U64,
},
PumpFeesBorshFieldDescriptor {
name: "token_amount",
kind: PumpFeesBorshFieldKind::U64,
},
PumpFeesBorshFieldDescriptor {
name: "destination",
kind: PumpFeesBorshFieldKind::Pubkey,
},
PumpFeesBorshFieldDescriptor {
name: "buyback_vault",
kind: PumpFeesBorshFieldKind::Pubkey,
},
PumpFeesBorshFieldDescriptor {
name: "mint",
kind: PumpFeesBorshFieldKind::Pubkey,
},
];
const PUMP_FEES_EVENT_UPDATE_ADMIN_EVENT_FIELDS: &[PumpFeesBorshFieldDescriptor] = &[
PumpFeesBorshFieldDescriptor {
name: "timestamp",
kind: PumpFeesBorshFieldKind::I64,
},
PumpFeesBorshFieldDescriptor {
name: "old_admin",
kind: PumpFeesBorshFieldKind::Pubkey,
},
PumpFeesBorshFieldDescriptor {
name: "new_admin",
kind: PumpFeesBorshFieldKind::Pubkey,
},
];
const PUMP_FEES_EVENT_UPDATE_FEE_CONFIG_EVENT_FIELDS: &[PumpFeesBorshFieldDescriptor] = &[
PumpFeesBorshFieldDescriptor {
name: "timestamp",
kind: PumpFeesBorshFieldKind::I64,
},
PumpFeesBorshFieldDescriptor {
name: "admin",
kind: PumpFeesBorshFieldKind::Pubkey,
},
PumpFeesBorshFieldDescriptor {
name: "fee_config",
kind: PumpFeesBorshFieldKind::Pubkey,
},
PumpFeesBorshFieldDescriptor {
name: "fee_tiers",
kind: PumpFeesBorshFieldKind::FeeTierVec,
},
PumpFeesBorshFieldDescriptor {
name: "flat_fees",
kind: PumpFeesBorshFieldKind::Fees,
},
];
const PUMP_FEES_EVENT_UPDATE_FEE_SHARES_EVENT_FIELDS: &[PumpFeesBorshFieldDescriptor] = &[
PumpFeesBorshFieldDescriptor {
name: "timestamp",
kind: PumpFeesBorshFieldKind::I64,
},
PumpFeesBorshFieldDescriptor {
name: "mint",
kind: PumpFeesBorshFieldKind::Pubkey,
},
PumpFeesBorshFieldDescriptor {
name: "sharing_config",
kind: PumpFeesBorshFieldKind::Pubkey,
},
PumpFeesBorshFieldDescriptor {
name: "admin",
kind: PumpFeesBorshFieldKind::Pubkey,
},
PumpFeesBorshFieldDescriptor {
name: "new_shareholders",
kind: PumpFeesBorshFieldKind::ShareholderVec,
},
PumpFeesBorshFieldDescriptor {
name: "version",
kind: PumpFeesBorshFieldKind::U8,
},
];
const PUMP_FEES_EVENT_UPDATE_STABLE_FEE_CONFIG_EVENT_FIELDS: &[PumpFeesBorshFieldDescriptor] = &[
PumpFeesBorshFieldDescriptor {
name: "timestamp",
kind: PumpFeesBorshFieldKind::I64,
},
PumpFeesBorshFieldDescriptor {
name: "admin",
kind: PumpFeesBorshFieldKind::Pubkey,
},
PumpFeesBorshFieldDescriptor {
name: "fee_config",
kind: PumpFeesBorshFieldKind::Pubkey,
},
PumpFeesBorshFieldDescriptor {
name: "stable_fee_tiers",
kind: PumpFeesBorshFieldKind::FeeTierVec,
},
PumpFeesBorshFieldDescriptor {
name: "flat_fees",
kind: PumpFeesBorshFieldKind::Fees,
},
];
const PUMP_FEES_EVENT_UPSERT_FEE_TIERS_EVENT_FIELDS: &[PumpFeesBorshFieldDescriptor] = &[
PumpFeesBorshFieldDescriptor {
name: "timestamp",
kind: PumpFeesBorshFieldKind::I64,
},
PumpFeesBorshFieldDescriptor {
name: "admin",
kind: PumpFeesBorshFieldKind::Pubkey,
},
PumpFeesBorshFieldDescriptor {
name: "fee_config",
kind: PumpFeesBorshFieldKind::Pubkey,
},
PumpFeesBorshFieldDescriptor {
name: "fee_tiers",
kind: PumpFeesBorshFieldKind::FeeTierVec,
},
PumpFeesBorshFieldDescriptor {
name: "offset",
kind: PumpFeesBorshFieldKind::U8,
},
];
const PUMP_FEES_EVENT_UPSERT_STABLE_FEE_TIERS_EVENT_FIELDS: &[PumpFeesBorshFieldDescriptor] = &[
PumpFeesBorshFieldDescriptor {
name: "timestamp",
kind: PumpFeesBorshFieldKind::I64,
},
PumpFeesBorshFieldDescriptor {
name: "admin",
kind: PumpFeesBorshFieldKind::Pubkey,
},
PumpFeesBorshFieldDescriptor {
name: "fee_config",
kind: PumpFeesBorshFieldKind::Pubkey,
},
PumpFeesBorshFieldDescriptor {
name: "stable_fee_tiers",
kind: PumpFeesBorshFieldKind::FeeTierVec,
},
PumpFeesBorshFieldDescriptor {
name: "offset",
kind: PumpFeesBorshFieldKind::U8,
},
];
#[derive(Debug, Clone)]
struct PumpFeesInstructionData {
spec: PumpFeesInstructionSpec,
discriminator_hex: std::string::String,
args_json: serde_json::Value,
}
#[derive(Debug, Clone)]
struct PumpFeesAnchorEventData {
spec: PumpFeesAnchorEventSpec,
discriminator_hex: std::string::String,
payload_size: usize,
fields_json: serde_json::Value,
}
/// Decoded Pump Fees instruction or Anchor event retained for coverage/materialization.
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
pub struct PumpFeesInstructionDecoded {
/// Parent transaction internal id.
pub transaction_id: i64,
/// Parent instruction internal id.
pub instruction_id: i64,
/// Decoded program id.
pub program_id: std::string::String,
/// Normalized event kind.
pub event_kind: std::string::String,
/// Best-effort accounting/config account.
pub pool_account: std::option::Option<std::string::String>,
/// Best-effort base/subject mint.
pub token_a_mint: std::option::Option<std::string::String>,
/// Best-effort quote/fee mint.
pub token_b_mint: std::option::Option<std::string::String>,
/// Best-effort secondary account used as lp/config surrogate.
pub lp_mint: std::option::Option<std::string::String>,
/// Decoded payload with instruction/event fields and materialization aliases.
pub payload_json: serde_json::Value,
}
/// Decoded Pump Fees event.
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
pub enum PumpFeesDecodedEvent {
/// Decoded on-chain instruction.
Instruction(PumpFeesInstructionDecoded),
/// Decoded Anchor `Program data` event.
AnchorEvent(PumpFeesInstructionDecoded),
}
/// Pump Fees decoder.
#[derive(Debug, Clone, Default)]
pub struct PumpFeesDecoder;
impl PumpFeesDecoder {
/// Creates a new decoder.
pub fn new() -> Self {
return Self;
}
/// Decodes one projected transaction into Pump Fees instruction and Anchor events.
pub fn decode_transaction(
&self,
transaction: &crate::ChainTransactionDto,
instructions: &[crate::ChainInstructionDto],
) -> Result<std::vec::Vec<crate::PumpFeesDecodedEvent>, crate::Error> {
let transaction_id = match transaction.id {
Some(transaction_id) => transaction_id,
None => {
return Err(crate::Error::InvalidState(format!(
"chain transaction '{}' has no internal id",
transaction.signature
)));
},
};
let transaction_json_result =
serde_json::from_str::<serde_json::Value>(transaction.transaction_json.as_str());
let transaction_json = match transaction_json_result {
Ok(transaction_json) => transaction_json,
Err(error) => {
return Err(crate::Error::Json(format!(
"cannot parse transaction_json for signature '{}': {}",
transaction.signature, error
)));
},
};
let log_messages = extract_log_messages(&transaction_json);
let anchor_events_result = decode_pump_fees_anchor_events(log_messages.as_slice());
let anchor_events = match anchor_events_result {
Ok(anchor_events) => anchor_events,
Err(error) => return Err(error),
};
let mut decoded_events = std::vec::Vec::new();
let mut pump_instruction_links = std::vec::Vec::new();
for instruction in instructions {
let program_id = match &instruction.program_id {
Some(program_id) => program_id,
None => continue,
};
if program_id.as_str() != crate::PUMP_FEES_PROGRAM_ID {
continue;
}
let instruction_id = match instruction.id {
Some(instruction_id) => instruction_id,
None => continue,
};
let instruction_data_result =
parse_pump_fees_instruction_data(instruction.data_json.as_ref());
let instruction_data = match instruction_data_result {
Ok(instruction_data) => instruction_data,
Err(error) => return Err(error),
};
let instruction_data = match instruction_data {
Some(instruction_data) => instruction_data,
None => continue,
};
let accounts_result = parse_accounts_json(instruction.accounts_json.as_str());
let accounts = match accounts_result {
Ok(accounts) => accounts,
Err(error) => return Err(error),
};
let parsed_json_result = parse_optional_parsed_json(instruction.parsed_json.as_ref());
let parsed_json = match parsed_json_result {
Ok(parsed_json) => parsed_json,
Err(error) => return Err(error),
};
let accounts_by_name = accounts_by_name_json(parsed_json.as_ref(), accounts.as_slice());
let mut payload = serde_json::Map::new();
payload
.insert("decoder".to_string(), serde_json::Value::String("pump_fees".to_string()));
payload.insert(
"signature".to_string(),
serde_json::Value::String(transaction.signature.clone()),
);
payload.insert("instructionId".to_string(), serde_json::json!(instruction_id));
payload.insert(
"instructionIndex".to_string(),
serde_json::json!(instruction.instruction_index),
);
if let Some(inner_instruction_index) = instruction.inner_instruction_index {
payload.insert(
"innerInstructionIndex".to_string(),
serde_json::json!(inner_instruction_index),
);
}
payload.insert("programId".to_string(), serde_json::Value::String(program_id.clone()));
payload.insert(
"instructionName".to_string(),
serde_json::Value::String(instruction_data.spec.name.to_string()),
);
payload.insert(
"discriminatorHex".to_string(),
serde_json::Value::String(instruction_data.discriminator_hex.clone()),
);
payload.insert("decodedArguments".to_string(), instruction_data.args_json.clone());
payload.insert("accounts".to_string(), serde_json::json!(accounts));
payload.insert("accountsByName".to_string(), accounts_by_name.clone());
add_materialization_aliases(
&mut payload,
instruction_data.spec.name,
&instruction_data.args_json,
&accounts_by_name,
);
let payload_json = serde_json::Value::Object(payload);
let pool_account = payload_string(
&payload_json,
&[
"feeConfig",
"fee_config",
"feeProgramGlobal",
"fee_program_global",
"sharingConfig",
"sharing_config",
"socialFeePda",
"social_fee_pda",
"donationFeePda",
"donation_fee_pda",
"buybackVault",
"buyback_vault",
"global",
],
);
let token_a_mint = payload_string(&payload_json, &["mint", "baseMint", "base_mint"]);
let token_b_mint = match payload_string(&payload_json, &["quoteMint", "quote_mint"]) {
Some(quote_mint) => Some(quote_mint),
None => {
if event_kind_is_buyback_or_fee(instruction_data.spec.name) {
Some(crate::WSOL_MINT_ID.to_string())
} else {
None
}
},
};
let lp_mint = payload_string(
&payload_json,
&[
"sharingConfig",
"sharing_config",
"buybackVaultAta",
"buyback_vault_ata",
"socialFeePda",
"social_fee_pda",
"donationFeePda",
"donation_fee_pda",
],
);
decoded_events.push(crate::PumpFeesDecodedEvent::Instruction(
PumpFeesInstructionDecoded {
transaction_id,
instruction_id,
program_id: program_id.clone(),
event_kind: format!("pump_fees.{}", instruction_data.spec.name),
pool_account,
token_a_mint,
token_b_mint,
lp_mint,
payload_json,
},
));
pump_instruction_links.push((
instruction.instruction_index,
instruction_id,
accounts_by_name,
));
}
for (event_index, anchor_event) in anchor_events.iter().enumerate() {
let instruction_id = match instruction_id_for_anchor_event(
event_index,
pump_instruction_links.as_slice(),
) {
Some(instruction_id) => instruction_id,
None => continue,
};
let accounts_by_name =
accounts_by_name_for_anchor_event(event_index, pump_instruction_links.as_slice());
let mut payload = serde_json::Map::new();
payload
.insert("decoder".to_string(), serde_json::Value::String("pump_fees".to_string()));
payload.insert(
"signature".to_string(),
serde_json::Value::String(transaction.signature.clone()),
);
payload.insert("instructionId".to_string(), serde_json::json!(instruction_id));
payload.insert("anchorEventIndex".to_string(), serde_json::json!(event_index));
payload.insert(
"programId".to_string(),
serde_json::Value::String(crate::PUMP_FEES_PROGRAM_ID.to_string()),
);
payload.insert(
"eventName".to_string(),
serde_json::Value::String(anchor_event.spec.name.to_string()),
);
payload.insert(
"discriminatorHex".to_string(),
serde_json::Value::String(anchor_event.discriminator_hex.clone()),
);
payload.insert(
"anchorEventPayloadSize".to_string(),
serde_json::json!(anchor_event.payload_size),
);
payload.insert("decodedEvent".to_string(), anchor_event.fields_json.clone());
add_materialization_aliases(
&mut payload,
anchor_event.spec.name,
&anchor_event.fields_json,
&accounts_by_name,
);
let payload_json = serde_json::Value::Object(payload);
let pool_account = payload_string(
&payload_json,
&[
"feeConfig",
"fee_config",
"feeProgramGlobal",
"fee_program_global",
"sharingConfig",
"sharing_config",
"socialFeePda",
"social_fee_pda",
"donationFeePda",
"donation_fee_pda",
"buybackVault",
"buyback_vault",
"global",
],
);
let token_a_mint = payload_string(&payload_json, &["mint", "baseMint", "base_mint"]);
let token_b_mint = payload_string(&payload_json, &["quoteMint", "quote_mint"]);
let lp_mint = payload_string(
&payload_json,
&[
"sharingConfig",
"sharing_config",
"socialFeePda",
"social_fee_pda",
"donationFeePda",
"donation_fee_pda",
"buybackVault",
"buyback_vault",
],
);
decoded_events.push(crate::PumpFeesDecodedEvent::AnchorEvent(
PumpFeesInstructionDecoded {
transaction_id,
instruction_id,
program_id: crate::PUMP_FEES_PROGRAM_ID.to_string(),
event_kind: anchor_event.spec.event_kind.to_string(),
pool_account,
token_a_mint,
token_b_mint,
lp_mint,
payload_json,
},
));
}
return Ok(decoded_events);
}
}
fn pump_fees_instruction_spec(
discriminator: [u8; 8],
) -> std::option::Option<PumpFeesInstructionSpec> {
match discriminator {
PUMP_FEES_CLAIM_SOCIAL_FEE_PDA_DISCRIMINATOR => {
return Some(PumpFeesInstructionSpec {
name: "claim_social_fee_pda",
fields: PUMP_FEES_INSTRUCTION_CLAIM_SOCIAL_FEE_PDA_FIELDS,
});
},
PUMP_FEES_CLAIM_SOCIAL_FEE_PDA_V2_DISCRIMINATOR => {
return Some(PumpFeesInstructionSpec {
name: "claim_social_fee_pda_v2",
fields: PUMP_FEES_INSTRUCTION_CLAIM_SOCIAL_FEE_PDA_V2_FIELDS,
});
},
PUMP_FEES_CRANK_DONATION_FEE_PDA_DISCRIMINATOR => {
return Some(PumpFeesInstructionSpec {
name: "crank_donation_fee_pda",
fields: PUMP_FEES_INSTRUCTION_CRANK_DONATION_FEE_PDA_FIELDS,
});
},
PUMP_FEES_CREATE_DONATION_FEE_PDA_DISCRIMINATOR => {
return Some(PumpFeesInstructionSpec {
name: "create_donation_fee_pda",
fields: PUMP_FEES_INSTRUCTION_CREATE_DONATION_FEE_PDA_FIELDS,
});
},
PUMP_FEES_CREATE_FEE_SHARING_CONFIG_DISCRIMINATOR => {
return Some(PumpFeesInstructionSpec {
name: "create_fee_sharing_config",
fields: PUMP_FEES_INSTRUCTION_CREATE_FEE_SHARING_CONFIG_FIELDS,
});
},
PUMP_FEES_CREATE_SOCIAL_FEE_PDA_DISCRIMINATOR => {
return Some(PumpFeesInstructionSpec {
name: "create_social_fee_pda",
fields: PUMP_FEES_INSTRUCTION_CREATE_SOCIAL_FEE_PDA_FIELDS,
});
},
PUMP_FEES_EXTEND_FEE_CONFIG_DISCRIMINATOR => {
return Some(PumpFeesInstructionSpec {
name: "extend_fee_config",
fields: PUMP_FEES_INSTRUCTION_EXTEND_FEE_CONFIG_FIELDS,
});
},
PUMP_FEES_GET_FEES_DISCRIMINATOR => {
return Some(PumpFeesInstructionSpec {
name: "get_fees",
fields: PUMP_FEES_INSTRUCTION_GET_FEES_FIELDS,
});
},
PUMP_FEES_INITIALIZE_BUYBACK_DISCRIMINATOR => {
return Some(PumpFeesInstructionSpec {
name: "initialize_buyback",
fields: PUMP_FEES_INSTRUCTION_INITIALIZE_BUYBACK_FIELDS,
});
},
PUMP_FEES_INITIALIZE_FEE_CONFIG_DISCRIMINATOR => {
return Some(PumpFeesInstructionSpec {
name: "initialize_fee_config",
fields: PUMP_FEES_INSTRUCTION_INITIALIZE_FEE_CONFIG_FIELDS,
});
},
PUMP_FEES_INITIALIZE_FEE_PROGRAM_GLOBAL_DISCRIMINATOR => {
return Some(PumpFeesInstructionSpec {
name: "initialize_fee_program_global",
fields: PUMP_FEES_INSTRUCTION_INITIALIZE_FEE_PROGRAM_GLOBAL_FIELDS,
});
},
PUMP_FEES_RESET_FEE_SHARING_CONFIG_DISCRIMINATOR => {
return Some(PumpFeesInstructionSpec {
name: "reset_fee_sharing_config",
fields: PUMP_FEES_INSTRUCTION_RESET_FEE_SHARING_CONFIG_FIELDS,
});
},
PUMP_FEES_RESET_FEE_SHARING_CONFIG_V2_DISCRIMINATOR => {
return Some(PumpFeesInstructionSpec {
name: "reset_fee_sharing_config_v2",
fields: PUMP_FEES_INSTRUCTION_RESET_FEE_SHARING_CONFIG_V2_FIELDS,
});
},
PUMP_FEES_REVOKE_FEE_SHARING_AUTHORITY_DISCRIMINATOR => {
return Some(PumpFeesInstructionSpec {
name: "revoke_fee_sharing_authority",
fields: PUMP_FEES_INSTRUCTION_REVOKE_FEE_SHARING_AUTHORITY_FIELDS,
});
},
PUMP_FEES_SET_AUTHORITY_DISCRIMINATOR => {
return Some(PumpFeesInstructionSpec {
name: "set_authority",
fields: PUMP_FEES_INSTRUCTION_SET_AUTHORITY_FIELDS,
});
},
PUMP_FEES_SET_CLAIM_RATE_LIMIT_DISCRIMINATOR => {
return Some(PumpFeesInstructionSpec {
name: "set_claim_rate_limit",
fields: PUMP_FEES_INSTRUCTION_SET_CLAIM_RATE_LIMIT_FIELDS,
});
},
PUMP_FEES_SET_DISABLE_FLAGS_DISCRIMINATOR => {
return Some(PumpFeesInstructionSpec {
name: "set_disable_flags",
fields: PUMP_FEES_INSTRUCTION_SET_DISABLE_FLAGS_FIELDS,
});
},
PUMP_FEES_SET_SOCIAL_CLAIM_AUTHORITY_DISCRIMINATOR => {
return Some(PumpFeesInstructionSpec {
name: "set_social_claim_authority",
fields: PUMP_FEES_INSTRUCTION_SET_SOCIAL_CLAIM_AUTHORITY_FIELDS,
});
},
PUMP_FEES_SWEEP_BUYBACK_DISCRIMINATOR => {
return Some(PumpFeesInstructionSpec {
name: "sweep_buyback",
fields: PUMP_FEES_INSTRUCTION_SWEEP_BUYBACK_FIELDS,
});
},
PUMP_FEES_TRANSFER_FEE_SHARING_AUTHORITY_DISCRIMINATOR => {
return Some(PumpFeesInstructionSpec {
name: "transfer_fee_sharing_authority",
fields: PUMP_FEES_INSTRUCTION_TRANSFER_FEE_SHARING_AUTHORITY_FIELDS,
});
},
PUMP_FEES_UPDATE_ADMIN_DISCRIMINATOR => {
return Some(PumpFeesInstructionSpec {
name: "update_admin",
fields: PUMP_FEES_INSTRUCTION_UPDATE_ADMIN_FIELDS,
});
},
PUMP_FEES_UPDATE_BUYBACK_AUTHORITY_DISCRIMINATOR => {
return Some(PumpFeesInstructionSpec {
name: "update_buyback_authority",
fields: PUMP_FEES_INSTRUCTION_UPDATE_BUYBACK_AUTHORITY_FIELDS,
});
},
PUMP_FEES_UPDATE_BUYBACK_CLAIM_RATE_LIMIT_DISCRIMINATOR => {
return Some(PumpFeesInstructionSpec {
name: "update_buyback_claim_rate_limit",
fields: PUMP_FEES_INSTRUCTION_UPDATE_BUYBACK_CLAIM_RATE_LIMIT_FIELDS,
});
},
PUMP_FEES_UPDATE_FEE_CONFIG_DISCRIMINATOR => {
return Some(PumpFeesInstructionSpec {
name: "update_fee_config",
fields: PUMP_FEES_INSTRUCTION_UPDATE_FEE_CONFIG_FIELDS,
});
},
PUMP_FEES_UPDATE_FEE_SHARES_DISCRIMINATOR => {
return Some(PumpFeesInstructionSpec {
name: "update_fee_shares",
fields: PUMP_FEES_INSTRUCTION_UPDATE_FEE_SHARES_FIELDS,
});
},
PUMP_FEES_UPDATE_FEE_SHARES_V2_DISCRIMINATOR => {
return Some(PumpFeesInstructionSpec {
name: "update_fee_shares_v2",
fields: PUMP_FEES_INSTRUCTION_UPDATE_FEE_SHARES_V2_FIELDS,
});
},
PUMP_FEES_UPDATE_STABLE_FEE_CONFIG_DISCRIMINATOR => {
return Some(PumpFeesInstructionSpec {
name: "update_stable_fee_config",
fields: PUMP_FEES_INSTRUCTION_UPDATE_STABLE_FEE_CONFIG_FIELDS,
});
},
PUMP_FEES_UPSERT_FEE_TIERS_DISCRIMINATOR => {
return Some(PumpFeesInstructionSpec {
name: "upsert_fee_tiers",
fields: PUMP_FEES_INSTRUCTION_UPSERT_FEE_TIERS_FIELDS,
});
},
PUMP_FEES_UPSERT_STABLE_FEE_TIERS_DISCRIMINATOR => {
return Some(PumpFeesInstructionSpec {
name: "upsert_stable_fee_tiers",
fields: PUMP_FEES_INSTRUCTION_UPSERT_STABLE_FEE_TIERS_FIELDS,
});
},
_ => return None,
}
}
fn pump_fees_anchor_event_spec(
discriminator: [u8; 8],
) -> std::option::Option<PumpFeesAnchorEventSpec> {
match discriminator {
PUMP_FEES_CREATE_FEE_SHARING_CONFIG_EVENT_DISCRIMINATOR => {
return Some(PumpFeesAnchorEventSpec {
name: "CreateFeeSharingConfigEvent",
event_kind: "pump_fees.create_fee_sharing_config_event",
fields: PUMP_FEES_EVENT_CREATE_FEE_SHARING_CONFIG_EVENT_FIELDS,
});
},
PUMP_FEES_DONATION_FEE_PDA_CRANKED_DISCRIMINATOR => {
return Some(PumpFeesAnchorEventSpec {
name: "DonationFeePdaCranked",
event_kind: "pump_fees.donation_fee_pda_cranked",
fields: PUMP_FEES_EVENT_DONATION_FEE_PDA_CRANKED_FIELDS,
});
},
PUMP_FEES_DONATION_FEE_PDA_CREATED_DISCRIMINATOR => {
return Some(PumpFeesAnchorEventSpec {
name: "DonationFeePdaCreated",
event_kind: "pump_fees.donation_fee_pda_created",
fields: PUMP_FEES_EVENT_DONATION_FEE_PDA_CREATED_FIELDS,
});
},
PUMP_FEES_EXTEND_FEE_CONFIG_EVENT_DISCRIMINATOR => {
return Some(PumpFeesAnchorEventSpec {
name: "ExtendFeeConfigEvent",
event_kind: "pump_fees.extend_fee_config_event",
fields: PUMP_FEES_EVENT_EXTEND_FEE_CONFIG_EVENT_FIELDS,
});
},
PUMP_FEES_INITIALIZE_FEE_CONFIG_EVENT_DISCRIMINATOR => {
return Some(PumpFeesAnchorEventSpec {
name: "InitializeFeeConfigEvent",
event_kind: "pump_fees.initialize_fee_config_event",
fields: PUMP_FEES_EVENT_INITIALIZE_FEE_CONFIG_EVENT_FIELDS,
});
},
PUMP_FEES_INITIALIZE_FEE_PROGRAM_GLOBAL_EVENT_DISCRIMINATOR => {
return Some(PumpFeesAnchorEventSpec {
name: "InitializeFeeProgramGlobalEvent",
event_kind: "pump_fees.initialize_fee_program_global_event",
fields: PUMP_FEES_EVENT_INITIALIZE_FEE_PROGRAM_GLOBAL_EVENT_FIELDS,
});
},
PUMP_FEES_RESET_FEE_SHARING_CONFIG_EVENT_DISCRIMINATOR => {
return Some(PumpFeesAnchorEventSpec {
name: "ResetFeeSharingConfigEvent",
event_kind: "pump_fees.reset_fee_sharing_config_event",
fields: PUMP_FEES_EVENT_RESET_FEE_SHARING_CONFIG_EVENT_FIELDS,
});
},
PUMP_FEES_SET_AUTHORITY_EVENT_DISCRIMINATOR => {
return Some(PumpFeesAnchorEventSpec {
name: "SetAuthorityEvent",
event_kind: "pump_fees.set_authority_event",
fields: PUMP_FEES_EVENT_SET_AUTHORITY_EVENT_FIELDS,
});
},
PUMP_FEES_SET_CLAIM_RATE_LIMIT_EVENT_DISCRIMINATOR => {
return Some(PumpFeesAnchorEventSpec {
name: "SetClaimRateLimitEvent",
event_kind: "pump_fees.set_claim_rate_limit_event",
fields: PUMP_FEES_EVENT_SET_CLAIM_RATE_LIMIT_EVENT_FIELDS,
});
},
PUMP_FEES_SET_DISABLE_FLAGS_EVENT_DISCRIMINATOR => {
return Some(PumpFeesAnchorEventSpec {
name: "SetDisableFlagsEvent",
event_kind: "pump_fees.set_disable_flags_event",
fields: PUMP_FEES_EVENT_SET_DISABLE_FLAGS_EVENT_FIELDS,
});
},
PUMP_FEES_SET_SOCIAL_CLAIM_AUTHORITY_EVENT_DISCRIMINATOR => {
return Some(PumpFeesAnchorEventSpec {
name: "SetSocialClaimAuthorityEvent",
event_kind: "pump_fees.set_social_claim_authority_event",
fields: PUMP_FEES_EVENT_SET_SOCIAL_CLAIM_AUTHORITY_EVENT_FIELDS,
});
},
PUMP_FEES_SOCIAL_FEE_PDA_CLAIMED_DISCRIMINATOR => {
return Some(PumpFeesAnchorEventSpec {
name: "SocialFeePdaClaimed",
event_kind: "pump_fees.social_fee_pda_claimed",
fields: PUMP_FEES_EVENT_SOCIAL_FEE_PDA_CLAIMED_FIELDS,
});
},
PUMP_FEES_SOCIAL_FEE_PDA_CREATED_DISCRIMINATOR => {
return Some(PumpFeesAnchorEventSpec {
name: "SocialFeePdaCreated",
event_kind: "pump_fees.social_fee_pda_created",
fields: PUMP_FEES_EVENT_SOCIAL_FEE_PDA_CREATED_FIELDS,
});
},
PUMP_FEES_SWEEP_BUYBACK_EVENT_DISCRIMINATOR => {
return Some(PumpFeesAnchorEventSpec {
name: "SweepBuybackEvent",
event_kind: "pump_fees.sweep_buyback_event",
fields: PUMP_FEES_EVENT_SWEEP_BUYBACK_EVENT_FIELDS,
});
},
PUMP_FEES_UPDATE_ADMIN_EVENT_DISCRIMINATOR => {
return Some(PumpFeesAnchorEventSpec {
name: "UpdateAdminEvent",
event_kind: "pump_fees.update_admin_event",
fields: PUMP_FEES_EVENT_UPDATE_ADMIN_EVENT_FIELDS,
});
},
PUMP_FEES_UPDATE_FEE_CONFIG_EVENT_DISCRIMINATOR => {
return Some(PumpFeesAnchorEventSpec {
name: "UpdateFeeConfigEvent",
event_kind: "pump_fees.update_fee_config_event",
fields: PUMP_FEES_EVENT_UPDATE_FEE_CONFIG_EVENT_FIELDS,
});
},
PUMP_FEES_UPDATE_FEE_SHARES_EVENT_DISCRIMINATOR => {
return Some(PumpFeesAnchorEventSpec {
name: "UpdateFeeSharesEvent",
event_kind: "pump_fees.update_fee_shares_event",
fields: PUMP_FEES_EVENT_UPDATE_FEE_SHARES_EVENT_FIELDS,
});
},
PUMP_FEES_UPDATE_STABLE_FEE_CONFIG_EVENT_DISCRIMINATOR => {
return Some(PumpFeesAnchorEventSpec {
name: "UpdateStableFeeConfigEvent",
event_kind: "pump_fees.update_stable_fee_config_event",
fields: PUMP_FEES_EVENT_UPDATE_STABLE_FEE_CONFIG_EVENT_FIELDS,
});
},
PUMP_FEES_UPSERT_FEE_TIERS_EVENT_DISCRIMINATOR => {
return Some(PumpFeesAnchorEventSpec {
name: "UpsertFeeTiersEvent",
event_kind: "pump_fees.upsert_fee_tiers_event",
fields: PUMP_FEES_EVENT_UPSERT_FEE_TIERS_EVENT_FIELDS,
});
},
PUMP_FEES_UPSERT_STABLE_FEE_TIERS_EVENT_DISCRIMINATOR => {
return Some(PumpFeesAnchorEventSpec {
name: "UpsertStableFeeTiersEvent",
event_kind: "pump_fees.upsert_stable_fee_tiers_event",
fields: PUMP_FEES_EVENT_UPSERT_STABLE_FEE_TIERS_EVENT_FIELDS,
});
},
_ => return None,
}
}
fn parse_pump_fees_instruction_data(
data_json: std::option::Option<&std::string::String>,
) -> Result<std::option::Option<PumpFeesInstructionData>, crate::Error> {
let data_text = match decode_instruction_data_text(data_json) {
Some(data_text) => data_text,
None => return Ok(None),
};
let decoded_result = bs58::decode(data_text.trim()).into_vec();
let decoded = match decoded_result {
Ok(decoded) => decoded,
Err(error) => {
return Err(crate::Error::InvalidState(format!(
"cannot base58-decode pump_fees instruction data: {}",
error
)));
},
};
if decoded.len() < 8 {
return Ok(None);
}
let discriminator = match read_8_byte_array(decoded.as_slice(), 0) {
Some(discriminator) => discriminator,
None => return Ok(None),
};
let spec = match pump_fees_instruction_spec(discriminator) {
Some(spec) => spec,
None => return Ok(None),
};
let decoded_fields_result = decode_borsh_fields(&decoded[8..], spec.fields);
let decoded_fields = match decoded_fields_result {
Ok(decoded_fields) => decoded_fields,
Err(error) => {
tracing::debug!(
decoder = "pump_fees",
discriminator_hex = bytes_to_hex(discriminator.as_slice()),
payload_size = decoded.len().saturating_sub(8),
error = %error,
"ignoring malformed pump_fees instruction payload"
);
return Ok(None);
},
};
return Ok(Some(PumpFeesInstructionData {
spec,
discriminator_hex: bytes_to_hex(discriminator.as_slice()),
args_json: decoded_fields,
}));
}
fn decode_pump_fees_anchor_events(
log_messages: &[std::string::String],
) -> Result<std::vec::Vec<PumpFeesAnchorEventData>, crate::Error> {
let mut events = std::vec::Vec::new();
for message in log_messages {
let encoded = match extract_program_data_base64(message.as_str()) {
Some(encoded) => encoded,
None => continue,
};
let event_result = decode_pump_fees_anchor_event_from_base64(encoded);
let event_option = match event_result {
Ok(event_option) => event_option,
Err(error) => return Err(error),
};
if let Some(event) = event_option {
events.push(event);
}
}
return Ok(events);
}
fn decode_pump_fees_anchor_event_from_base64(
encoded: &str,
) -> Result<std::option::Option<PumpFeesAnchorEventData>, crate::Error> {
let decoded = decode_base64_standard(encoded);
let decoded = match decoded {
Some(decoded) => decoded,
None => return Ok(None),
};
let payload = if decoded.len() >= 16
&& read_8_byte_array(decoded.as_slice(), 0)
== Some(PUMP_FEES_ANCHOR_SELF_CPI_LOG_DISCRIMINATOR)
{
&decoded[8..]
} else {
decoded.as_slice()
};
if payload.len() < 8 {
return Ok(None);
}
let discriminator = match read_8_byte_array(payload, 0) {
Some(discriminator) => discriminator,
None => return Ok(None),
};
let spec = match pump_fees_anchor_event_spec(discriminator) {
Some(spec) => spec,
None => return Ok(None),
};
let fields_result = decode_borsh_fields(&payload[8..], spec.fields);
let fields_json = match fields_result {
Ok(fields_json) => fields_json,
Err(error) => {
tracing::debug!(
decoder = "pump_fees",
discriminator_hex = bytes_to_hex(discriminator.as_slice()),
payload_size = payload.len().saturating_sub(8),
error = %error,
"ignoring malformed pump_fees anchor event payload"
);
return Ok(None);
},
};
return Ok(Some(PumpFeesAnchorEventData {
spec,
discriminator_hex: bytes_to_hex(discriminator.as_slice()),
payload_size: payload.len().saturating_sub(8),
fields_json,
}));
}
fn decode_borsh_fields(
data: &[u8],
fields: &[PumpFeesBorshFieldDescriptor],
) -> Result<serde_json::Value, crate::Error> {
let mut offset = 0_usize;
let mut object = serde_json::Map::new();
for field in fields {
let decoded_result = read_borsh_field_value(data, offset, field.kind);
let (value, next_offset) = match decoded_result {
Ok(value) => value,
Err(error) => return Err(error),
};
offset = next_offset;
object.insert(field.name.to_string(), value);
}
object.insert("payloadBytesConsumed".to_string(), serde_json::json!(offset));
object.insert("payloadBytesTotal".to_string(), serde_json::json!(data.len()));
return Ok(serde_json::Value::Object(object));
}
fn read_borsh_field_value(
data: &[u8],
offset: usize,
kind: PumpFeesBorshFieldKind,
) -> Result<(serde_json::Value, usize), crate::Error> {
match kind {
PumpFeesBorshFieldKind::U8 => return read_u8_value(data, offset),
PumpFeesBorshFieldKind::U64 => return read_u64_value(data, offset),
PumpFeesBorshFieldKind::I64 => return read_i64_value(data, offset),
PumpFeesBorshFieldKind::U128 => return read_u128_value(data, offset),
PumpFeesBorshFieldKind::Bool => return read_bool_value(data, offset),
PumpFeesBorshFieldKind::Pubkey => return read_pubkey_value(data, offset),
PumpFeesBorshFieldKind::String => return read_string_value(data, offset),
PumpFeesBorshFieldKind::OptionBool => return read_option_bool_value(data, offset),
PumpFeesBorshFieldKind::OptionPubkey => return read_option_pubkey_value(data, offset),
PumpFeesBorshFieldKind::Fees => return read_fees_value(data, offset),
PumpFeesBorshFieldKind::ConfigStatus => return read_config_status_value(data, offset),
PumpFeesBorshFieldKind::ShareholderVec => return read_shareholder_vec_value(data, offset),
PumpFeesBorshFieldKind::FeeTierVec => return read_fee_tier_vec_value(data, offset),
}
}
fn read_u8_value(data: &[u8], offset: usize) -> Result<(serde_json::Value, usize), crate::Error> {
if offset.saturating_add(1) > data.len() {
return Err(crate::Error::InvalidState("pump_fees u8 field exceeds payload".to_string()));
}
return Ok((serde_json::json!(data[offset]), offset.saturating_add(1)));
}
fn read_u16_value(data: &[u8], offset: usize) -> Result<(serde_json::Value, usize), crate::Error> {
if offset.saturating_add(2) > data.len() {
return Err(crate::Error::InvalidState("pump_fees u16 field exceeds payload".to_string()));
}
let mut bytes = [0_u8; 2];
bytes.copy_from_slice(&data[offset..offset + 2]);
return Ok((serde_json::json!(u16::from_le_bytes(bytes)), offset.saturating_add(2)));
}
fn read_u32_raw(data: &[u8], offset: usize) -> Result<(u32, usize), crate::Error> {
if offset.saturating_add(4) > data.len() {
return Err(crate::Error::InvalidState("pump_fees u32 field exceeds payload".to_string()));
}
let mut bytes = [0_u8; 4];
bytes.copy_from_slice(&data[offset..offset + 4]);
return Ok((u32::from_le_bytes(bytes), offset.saturating_add(4)));
}
fn read_u64_value(data: &[u8], offset: usize) -> Result<(serde_json::Value, usize), crate::Error> {
if offset.saturating_add(8) > data.len() {
return Err(crate::Error::InvalidState("pump_fees u64 field exceeds payload".to_string()));
}
let mut bytes = [0_u8; 8];
bytes.copy_from_slice(&data[offset..offset + 8]);
let value = u64::from_le_bytes(bytes);
return Ok((serde_json::Value::String(value.to_string()), offset.saturating_add(8)));
}
fn read_i64_value(data: &[u8], offset: usize) -> Result<(serde_json::Value, usize), crate::Error> {
if offset.saturating_add(8) > data.len() {
return Err(crate::Error::InvalidState("pump_fees i64 field exceeds payload".to_string()));
}
let mut bytes = [0_u8; 8];
bytes.copy_from_slice(&data[offset..offset + 8]);
let value = i64::from_le_bytes(bytes);
return Ok((serde_json::Value::String(value.to_string()), offset.saturating_add(8)));
}
fn read_u128_value(data: &[u8], offset: usize) -> Result<(serde_json::Value, usize), crate::Error> {
if offset.saturating_add(16) > data.len() {
return Err(crate::Error::InvalidState("pump_fees u128 field exceeds payload".to_string()));
}
let mut bytes = [0_u8; 16];
bytes.copy_from_slice(&data[offset..offset + 16]);
let value = u128::from_le_bytes(bytes);
return Ok((serde_json::Value::String(value.to_string()), offset.saturating_add(16)));
}
fn read_bool_value(data: &[u8], offset: usize) -> Result<(serde_json::Value, usize), crate::Error> {
let value_result = read_u8_value(data, offset);
let (value, next_offset) = match value_result {
Ok(value) => value,
Err(error) => return Err(error),
};
let numeric = match value.as_u64() {
Some(numeric) => numeric,
None => 0,
};
return Ok((serde_json::Value::Bool(numeric != 0), next_offset));
}
fn read_pubkey_value(
data: &[u8],
offset: usize,
) -> Result<(serde_json::Value, usize), crate::Error> {
if offset.saturating_add(32) > data.len() {
return Err(crate::Error::InvalidState(
"pump_fees pubkey field exceeds payload".to_string(),
));
}
let encoded = bs58::encode(&data[offset..offset + 32]).into_string();
return Ok((serde_json::Value::String(encoded), offset.saturating_add(32)));
}
fn read_string_value(
data: &[u8],
offset: usize,
) -> Result<(serde_json::Value, usize), crate::Error> {
let length_result = read_u32_raw(data, offset);
let (length, mut current_offset) = match length_result {
Ok(value) => value,
Err(error) => return Err(error),
};
let length_usize = length as usize;
if current_offset.saturating_add(length_usize) > data.len() {
return Err(crate::Error::InvalidState(
"pump_fees string field exceeds payload".to_string(),
));
}
let text_result = std::str::from_utf8(&data[current_offset..current_offset + length_usize]);
let text = match text_result {
Ok(text) => text,
Err(error) => {
return Err(crate::Error::InvalidState(format!(
"pump_fees string field is not utf8: {}",
error
)));
},
};
current_offset = current_offset.saturating_add(length_usize);
return Ok((serde_json::Value::String(text.to_string()), current_offset));
}
fn read_option_bool_value(
data: &[u8],
offset: usize,
) -> Result<(serde_json::Value, usize), crate::Error> {
return read_bool_value(data, offset);
}
fn read_option_pubkey_value(
data: &[u8],
offset: usize,
) -> Result<(serde_json::Value, usize), crate::Error> {
let tag_result = read_u8_value(data, offset);
let (tag_value, mut current_offset) = match tag_result {
Ok(value) => value,
Err(error) => return Err(error),
};
let tag = match tag_value.as_u64() {
Some(tag) => tag,
None => 0,
};
if tag == 0 {
return Ok((serde_json::Value::Null, current_offset));
}
let pubkey_result = read_pubkey_value(data, current_offset);
let (pubkey, next_offset) = match pubkey_result {
Ok(value) => value,
Err(error) => return Err(error),
};
current_offset = next_offset;
return Ok((pubkey, current_offset));
}
fn read_fees_value(data: &[u8], offset: usize) -> Result<(serde_json::Value, usize), crate::Error> {
let lp_result = read_u64_value(data, offset);
let (lp_fee_bps, current_offset) = match lp_result {
Ok(value) => value,
Err(error) => return Err(error),
};
let protocol_result = read_u64_value(data, current_offset);
let (protocol_fee_bps, current_offset) = match protocol_result {
Ok(value) => value,
Err(error) => return Err(error),
};
let creator_result = read_u64_value(data, current_offset);
let (creator_fee_bps, current_offset) = match creator_result {
Ok(value) => value,
Err(error) => return Err(error),
};
let mut object = serde_json::Map::new();
object.insert("lp_fee_bps".to_string(), lp_fee_bps);
object.insert("protocol_fee_bps".to_string(), protocol_fee_bps);
object.insert("creator_fee_bps".to_string(), creator_fee_bps);
return Ok((serde_json::Value::Object(object), current_offset));
}
fn read_config_status_value(
data: &[u8],
offset: usize,
) -> Result<(serde_json::Value, usize), crate::Error> {
let status_result = read_u8_value(data, offset);
let (status_value, next_offset) = match status_result {
Ok(value) => value,
Err(error) => return Err(error),
};
let status_code = match status_value.as_u64() {
Some(status_code) => status_code,
None => 0,
};
let status_name = match status_code {
0 => "paused",
1 => "active",
_ => "unknown",
};
let mut object = serde_json::Map::new();
object.insert("code".to_string(), serde_json::json!(status_code));
object.insert("name".to_string(), serde_json::Value::String(status_name.to_string()));
return Ok((serde_json::Value::Object(object), next_offset));
}
fn read_shareholder_vec_value(
data: &[u8],
offset: usize,
) -> Result<(serde_json::Value, usize), crate::Error> {
let length_result = read_u32_raw(data, offset);
let (length, mut current_offset) = match length_result {
Ok(value) => value,
Err(error) => return Err(error),
};
let mut values = std::vec::Vec::new();
for _ in 0..length {
let address_result = read_pubkey_value(data, current_offset);
let (address, next_offset) = match address_result {
Ok(value) => value,
Err(error) => return Err(error),
};
current_offset = next_offset;
let share_result = read_u16_value(data, current_offset);
let (share_bps, next_offset) = match share_result {
Ok(value) => value,
Err(error) => return Err(error),
};
current_offset = next_offset;
let mut object = serde_json::Map::new();
object.insert("address".to_string(), address);
object.insert("share_bps".to_string(), share_bps);
values.push(serde_json::Value::Object(object));
}
return Ok((serde_json::Value::Array(values), current_offset));
}
fn read_fee_tier_vec_value(
data: &[u8],
offset: usize,
) -> Result<(serde_json::Value, usize), crate::Error> {
let length_result = read_u32_raw(data, offset);
let (length, mut current_offset) = match length_result {
Ok(value) => value,
Err(error) => return Err(error),
};
let mut values = std::vec::Vec::new();
for _ in 0..length {
let threshold_result = read_u128_value(data, current_offset);
let (threshold, next_offset) = match threshold_result {
Ok(value) => value,
Err(error) => return Err(error),
};
current_offset = next_offset;
let fees_result = read_fees_value(data, current_offset);
let (fees, next_offset) = match fees_result {
Ok(value) => value,
Err(error) => return Err(error),
};
current_offset = next_offset;
let mut object = serde_json::Map::new();
object.insert("market_cap_lamports_threshold".to_string(), threshold);
object.insert("fees".to_string(), fees);
values.push(serde_json::Value::Object(object));
}
return Ok((serde_json::Value::Array(values), current_offset));
}
fn add_materialization_aliases(
payload: &mut serde_json::Map<std::string::String, serde_json::Value>,
name: &str,
decoded: &serde_json::Value,
accounts_by_name: &serde_json::Value,
) {
copy_payload_alias(payload, decoded, accounts_by_name, "mint", "mint");
copy_payload_alias(payload, decoded, accounts_by_name, "base_mint", "baseMint");
copy_payload_alias(payload, decoded, accounts_by_name, "quote_mint", "quoteMint");
copy_payload_alias(payload, decoded, accounts_by_name, "fee_config", "feeConfig");
copy_payload_alias(
payload,
decoded,
accounts_by_name,
"fee_program_global",
"feeProgramGlobal",
);
copy_payload_alias(payload, decoded, accounts_by_name, "sharing_config", "sharingConfig");
copy_payload_alias(payload, decoded, accounts_by_name, "social_fee_pda", "socialFeePda");
copy_payload_alias(payload, decoded, accounts_by_name, "donation_fee_pda", "donationFeePda");
copy_payload_alias(payload, decoded, accounts_by_name, "buyback_vault", "buybackVault");
copy_payload_alias(payload, decoded, accounts_by_name, "admin", "admin");
copy_payload_alias(payload, decoded, accounts_by_name, "authority", "authority");
copy_payload_alias(payload, decoded, accounts_by_name, "recipient", "recipient");
copy_payload_alias(payload, decoded, accounts_by_name, "destination", "destination");
copy_payload_alias(payload, decoded, accounts_by_name, "signer", "signer");
copy_payload_alias(payload, decoded, accounts_by_name, "creator", "creator");
copy_payload_alias(payload, decoded, accounts_by_name, "new_authority", "newAuthority");
copy_payload_alias(payload, decoded, accounts_by_name, "new_admin", "newAdmin");
copy_payload_alias(payload, decoded, accounts_by_name, "amount", "amount");
copy_payload_alias(payload, decoded, accounts_by_name, "amount_claimed", "amountClaimed");
copy_payload_alias(payload, decoded, accounts_by_name, "sol_amount", "solAmount");
copy_payload_alias(payload, decoded, accounts_by_name, "token_amount", "tokenAmount");
let actor = first_string_value(
payload,
&[
"recipient",
"destination",
"signer",
"authority",
"admin",
"creator",
"newAuthority",
"newAdmin",
],
);
if let Some(actor) = actor {
payload.insert("actorWallet".to_string(), serde_json::Value::String(actor));
}
if name.contains("SocialFeePdaClaimed")
|| name == "claim_social_fee_pda"
|| name == "claim_social_fee_pda_v2"
{
if let Some(amount) = first_json_value(payload, &["amountClaimed", "amount"]) {
payload.insert("rewardAmountRaw".to_string(), amount);
}
if let Some(mint) = first_string_value(payload, &["quoteMint", "mint"]) {
payload.insert("rewardTokenMint".to_string(), serde_json::Value::String(mint));
}
}
if name.contains("DonationFee") || name.contains("Buyback") || name == "sweep_buyback" {
if let Some(amount) = first_json_value(payload, &["amount", "solAmount", "tokenAmount"]) {
payload.insert("feeAmountRaw".to_string(), amount);
}
if let Some(mint) = first_string_value(payload, &["quoteMint", "mint"]) {
payload.insert("feeTokenMint".to_string(), serde_json::Value::String(mint));
}
}
payload.insert(
"pumpFeesMaterializationPolicy".to_string(),
serde_json::Value::String(materialization_policy_for_name(name).to_string()),
);
}
fn materialization_policy_for_name(name: &str) -> &'static str {
if name == "get_fees" {
return "decoded_only_fee_calculation";
}
if name.contains("Claimed") || name.contains("Cranked") || name.contains("Sweep") {
return "materialize_if_successful_fee_or_reward";
}
if name.contains("Config")
|| name.contains("Authority")
|| name.contains("Admin")
|| name.contains("Tier")
|| name.contains("Disable")
|| name.contains("Buyback")
|| name.contains("Sharing")
|| name.contains("Created")
|| name.starts_with("create_")
|| name.starts_with("initialize_")
|| name.starts_with("update_")
|| name.starts_with("set_")
|| name.starts_with("reset_")
|| name.starts_with("extend_")
|| name.starts_with("upsert_")
{
return "materialize_if_successful_admin_or_lifecycle";
}
return "decoded_only_audit";
}
fn event_kind_is_buyback_or_fee(name: &str) -> bool {
return name.contains("fee") || name.contains("buyback") || name.contains("donation");
}
fn copy_payload_alias(
payload: &mut serde_json::Map<std::string::String, serde_json::Value>,
decoded: &serde_json::Value,
accounts_by_name: &serde_json::Value,
source_key: &str,
target_key: &str,
) {
if payload.get(target_key).is_some() {
return;
}
if let Some(value) = json_value_by_key(decoded, source_key) {
payload.insert(target_key.to_string(), value.clone());
return;
}
if let Some(value) = json_value_by_key(accounts_by_name, source_key) {
payload.insert(target_key.to_string(), value.clone());
}
}
fn json_value_by_key<'a>(
value: &'a serde_json::Value,
key: &str,
) -> std::option::Option<&'a serde_json::Value> {
if let Some(object) = value.as_object() {
if let Some(found) = object.get(key) {
return Some(found);
}
let camel = snake_to_camel(key);
if let Some(found) = object.get(camel.as_str()) {
return Some(found);
}
}
return None;
}
fn first_json_value(
payload: &serde_json::Map<std::string::String, serde_json::Value>,
keys: &[&str],
) -> std::option::Option<serde_json::Value> {
for key in keys {
if let Some(value) = payload.get(*key) {
return Some(value.clone());
}
}
return None;
}
fn first_string_value(
payload: &serde_json::Map<std::string::String, serde_json::Value>,
keys: &[&str],
) -> std::option::Option<std::string::String> {
for key in keys {
if let Some(value) = payload.get(*key) {
if let Some(text) = value.as_str() {
if !text.trim().is_empty() {
return Some(text.to_string());
}
}
}
}
return None;
}
fn payload_string(
payload: &serde_json::Value,
keys: &[&str],
) -> std::option::Option<std::string::String> {
if let Some(object) = payload.as_object() {
for key in keys {
if let Some(value) = object.get(*key) {
if let Some(text) = value.as_str() {
if !text.trim().is_empty() {
return Some(text.to_string());
}
}
}
let camel = snake_to_camel(key);
if let Some(value) = object.get(camel.as_str()) {
if let Some(text) = value.as_str() {
if !text.trim().is_empty() {
return Some(text.to_string());
}
}
}
}
for nested_key in &["decodedArguments", "decodedEvent", "accountsByName"] {
if let Some(nested) = object.get(*nested_key) {
let nested_value = payload_string(nested, keys);
if nested_value.is_some() {
return nested_value;
}
}
}
}
return None;
}
fn snake_to_camel(key: &str) -> std::string::String {
let mut result = std::string::String::new();
let mut uppercase_next = false;
for character in key.chars() {
if character == '_' {
uppercase_next = true;
continue;
}
if uppercase_next {
for upper in character.to_uppercase() {
result.push(upper);
}
uppercase_next = false;
} else {
result.push(character);
}
}
return result;
}
fn instruction_id_for_anchor_event(
event_index: usize,
links: &[(u32, i64, serde_json::Value)],
) -> std::option::Option<i64> {
if links.is_empty() {
return None;
}
if event_index < links.len() {
return Some(links[event_index].1);
}
return Some(links[links.len().saturating_sub(1)].1);
}
fn accounts_by_name_for_anchor_event(
event_index: usize,
links: &[(u32, i64, serde_json::Value)],
) -> serde_json::Value {
if links.is_empty() {
return serde_json::json!({});
}
if event_index < links.len() {
return links[event_index].2.clone();
}
return links[links.len().saturating_sub(1)].2.clone();
}
fn accounts_by_name_json(
parsed_json: std::option::Option<&serde_json::Value>,
accounts: &[std::string::String],
) -> serde_json::Value {
let mut object = serde_json::Map::new();
if let Some(parsed_json) = parsed_json {
if let Some(accounts_value) = parsed_json.get("accounts") {
if let Some(accounts_array) = accounts_value.as_array() {
for account in accounts_array {
let name = account.get("name").and_then(serde_json::Value::as_str);
let pubkey = account.get("pubkey").and_then(serde_json::Value::as_str);
if let (Some(name), Some(pubkey)) = (name, pubkey) {
object.insert(
name.to_string(),
serde_json::Value::String(pubkey.to_string()),
);
}
}
}
}
}
let fallback_names = [
"account0",
"account1",
"account2",
"account3",
"account4",
"account5",
"account6",
"account7",
"account8",
"account9",
"account10",
"account11",
"account12",
"account13",
"account14",
"account15",
"account16",
"account17",
"account18",
"account19",
"account20",
];
for (index, account) in accounts.iter().enumerate() {
if index >= fallback_names.len() {
continue;
}
object
.insert(fallback_names[index].to_string(), serde_json::Value::String(account.clone()));
}
return serde_json::Value::Object(object);
}
fn extract_program_data_base64(message: &str) -> std::option::Option<&str> {
let trimmed = message.trim();
if let Some(rest) = trimmed.strip_prefix("Program data: ") {
return Some(rest.trim());
}
return None;
}
fn decode_base64_standard(encoded: &str) -> std::option::Option<std::vec::Vec<u8>> {
use base64::Engine as _;
let decoded = base64::engine::general_purpose::STANDARD.decode(encoded.as_bytes());
match decoded {
Ok(decoded) => return Some(decoded),
Err(_) => return None,
}
}
fn extract_log_messages(
transaction_json: &serde_json::Value,
) -> std::vec::Vec<std::string::String> {
let mut messages = std::vec::Vec::new();
let meta = match transaction_json.get("meta") {
Some(meta) => meta,
None => return messages,
};
let logs = match meta.get("logMessages") {
Some(logs) => logs,
None => return messages,
};
let logs_array = match logs.as_array() {
Some(logs_array) => logs_array,
None => return messages,
};
for value in logs_array {
if let Some(text) = value.as_str() {
messages.push(text.to_string());
}
}
return messages;
}
fn parse_accounts_json(
accounts_json: &str,
) -> Result<std::vec::Vec<std::string::String>, crate::Error> {
let values_result = serde_json::from_str::<std::vec::Vec<serde_json::Value>>(accounts_json);
let values = match values_result {
Ok(values) => values,
Err(error) => {
return Err(crate::Error::Json(format!(
"cannot parse pump_fees accounts_json: {}",
error
)));
},
};
let mut accounts = std::vec::Vec::new();
for value in values {
if let Some(text) = value.as_str() {
accounts.push(text.to_string());
} else if let Some(object) = value.as_object() {
if let Some(pubkey) = object.get("pubkey").and_then(serde_json::Value::as_str) {
accounts.push(pubkey.to_string());
}
}
}
return Ok(accounts);
}
fn parse_optional_parsed_json(
parsed_json: std::option::Option<&std::string::String>,
) -> Result<std::option::Option<serde_json::Value>, crate::Error> {
let text = match parsed_json {
Some(text) => text,
None => return Ok(None),
};
let parsed = serde_json::from_str::<serde_json::Value>(text.as_str());
match parsed {
Ok(parsed) => return Ok(Some(parsed)),
Err(error) => {
return Err(crate::Error::Json(format!(
"cannot parse pump_fees parsed_json: {}",
error
)));
},
}
}
fn decode_instruction_data_text(
data_json: std::option::Option<&std::string::String>,
) -> std::option::Option<std::string::String> {
let data_json = match data_json {
Some(data_json) => data_json,
None => return None,
};
let value_result = serde_json::from_str::<serde_json::Value>(data_json.as_str());
if let Ok(value) = value_result {
if let Some(text) = value.as_str() {
return Some(text.to_string());
}
if let Some(object) = value.as_object() {
if let Some(text) = object.get("data").and_then(serde_json::Value::as_str) {
return Some(text.to_string());
}
}
}
let trimmed = data_json.trim();
if trimmed.is_empty() {
return None;
}
return Some(trimmed.to_string());
}
fn read_8_byte_array(data: &[u8], offset: usize) -> std::option::Option<[u8; 8]> {
if offset.saturating_add(8) > data.len() {
return None;
}
let mut bytes = [0_u8; 8];
bytes.copy_from_slice(&data[offset..offset + 8]);
return Some(bytes);
}
fn bytes_to_hex(data: &[u8]) -> std::string::String {
let mut text = std::string::String::new();
for byte in data {
text.push_str(format!("{:02x}", byte).as_str());
}
return text;
}
#[cfg(test)]
mod tests {
#[test]
fn decodes_get_fees_instruction_args() {
let mut data = std::vec::Vec::new();
data.extend_from_slice(&super::PUMP_FEES_GET_FEES_DISCRIMINATOR);
data.push(1_u8);
data.extend_from_slice(&123456789_u128.to_le_bytes());
data.extend_from_slice(&42_u64.to_le_bytes());
data.push(0_u8);
let encoded = bs58::encode(data).into_string();
let data_json = serde_json::json!(encoded).to_string();
let decoded_result = super::parse_pump_fees_instruction_data(Some(&data_json));
let decoded = match decoded_result {
Ok(Some(decoded)) => decoded,
Ok(None) => panic!("expected decoded get_fees"),
Err(error) => panic!("unexpected decode error: {}", error),
};
assert_eq!(decoded.spec.name, "get_fees");
assert_eq!(decoded.discriminator_hex, "e7257e55cf5b3f34");
assert_eq!(decoded.args_json["is_pump_pool"], serde_json::json!(true));
assert_eq!(decoded.args_json["market_cap_lamports"], serde_json::json!("123456789"));
assert_eq!(decoded.args_json["trade_size_lamports"], serde_json::json!("42"));
assert_eq!(decoded.args_json["is_new_quote_mint"], serde_json::json!(false));
}
#[test]
fn decodes_update_fee_shares_shareholders() {
let mut data = std::vec::Vec::new();
data.extend_from_slice(&super::PUMP_FEES_UPDATE_FEE_SHARES_DISCRIMINATOR);
data.extend_from_slice(&1_u32.to_le_bytes());
data.extend_from_slice(&[7_u8; 32]);
data.extend_from_slice(&2500_u16.to_le_bytes());
let encoded = bs58::encode(data).into_string();
let data_json = serde_json::json!(encoded).to_string();
let decoded_result = super::parse_pump_fees_instruction_data(Some(&data_json));
let decoded = match decoded_result {
Ok(Some(decoded)) => decoded,
Ok(None) => panic!("expected decoded update_fee_shares"),
Err(error) => panic!("unexpected decode error: {}", error),
};
assert_eq!(decoded.spec.name, "update_fee_shares");
assert_eq!(decoded.discriminator_hex, "bd0d8863bba4ed23");
assert_eq!(decoded.args_json["shareholders"][0]["share_bps"], serde_json::json!(2500));
}
#[test]
fn decodes_social_fee_claimed_anchor_event() {
let mut data = pump_fees_anchor_event_prefix(
&super::PUMP_FEES_SOCIAL_FEE_PDA_CLAIMED_DISCRIMINATOR,
);
data.extend_from_slice(&123_i64.to_le_bytes());
let user = "user-1".as_bytes();
data.extend_from_slice(&(user.len() as u32).to_le_bytes());
data.extend_from_slice(user);
data.push(2_u8);
data.extend_from_slice(&[1_u8; 32]);
data.extend_from_slice(&[2_u8; 32]);
data.extend_from_slice(&[3_u8; 32]);
data.extend_from_slice(&99_u64.to_le_bytes());
data.extend_from_slice(&100_u64.to_le_bytes());
data.extend_from_slice(&101_u64.to_le_bytes());
data.extend_from_slice(&102_u64.to_le_bytes());
data.extend_from_slice(&201_u64.to_le_bytes());
data.extend_from_slice(&[4_u8; 32]);
let decoded = decode_synthetic_anchor_event(data, "social fee event");
assert_eq!(decoded.spec.name, "SocialFeePdaClaimed");
assert_eq!(decoded.discriminator_hex, "3212c141edd2eaec");
assert_eq!(decoded.fields_json["user_id"], serde_json::json!("user-1"));
assert_eq!(decoded.fields_json["amount_claimed"], serde_json::json!("99"));
}
#[test]
fn decodes_unobserved_idl_admin_anchor_events() {
let mut authority_data = pump_fees_anchor_event_prefix(
&super::PUMP_FEES_SET_AUTHORITY_EVENT_DISCRIMINATOR,
);
authority_data.extend_from_slice(&11_i64.to_le_bytes());
authority_data.extend_from_slice(&[1_u8; 32]);
authority_data.extend_from_slice(&[2_u8; 32]);
let authority_event = decode_synthetic_anchor_event(authority_data, "set authority event");
assert_eq!(authority_event.spec.name, "SetAuthorityEvent");
assert_eq!(authority_event.discriminator_hex, "12af8442d0c957f2");
assert_eq!(authority_event.fields_json["timestamp"], serde_json::json!("11"));
assert_eq!(
authority_event.fields_json["old_authority"],
serde_json::json!(bs58::encode([1_u8; 32]).into_string())
);
assert_eq!(
authority_event.fields_json["new_authority"],
serde_json::json!(bs58::encode([2_u8; 32]).into_string())
);
let mut claim_rate_limit_data = pump_fees_anchor_event_prefix(
&super::PUMP_FEES_SET_CLAIM_RATE_LIMIT_EVENT_DISCRIMINATOR,
);
claim_rate_limit_data.extend_from_slice(&12_i64.to_le_bytes());
claim_rate_limit_data.extend_from_slice(&999_u64.to_le_bytes());
let claim_rate_limit_event =
decode_synthetic_anchor_event(claim_rate_limit_data, "set claim rate limit event");
assert_eq!(claim_rate_limit_event.spec.name, "SetClaimRateLimitEvent");
assert_eq!(claim_rate_limit_event.discriminator_hex, "0d8f8febb5133328");
assert_eq!(
claim_rate_limit_event.fields_json["claim_rate_limit"],
serde_json::json!("999")
);
let mut disable_flags_data = pump_fees_anchor_event_prefix(
&super::PUMP_FEES_SET_DISABLE_FLAGS_EVENT_DISCRIMINATOR,
);
disable_flags_data.extend_from_slice(&13_i64.to_le_bytes());
disable_flags_data.push(7_u8);
let disable_flags_event =
decode_synthetic_anchor_event(disable_flags_data, "set disable flags event");
assert_eq!(disable_flags_event.spec.name, "SetDisableFlagsEvent");
assert_eq!(disable_flags_event.discriminator_hex, "0508b3413137917e");
assert_eq!(
disable_flags_event.fields_json["disable_flags"],
serde_json::json!(7)
);
let mut social_claim_authority_data = pump_fees_anchor_event_prefix(
&super::PUMP_FEES_SET_SOCIAL_CLAIM_AUTHORITY_EVENT_DISCRIMINATOR,
);
social_claim_authority_data.extend_from_slice(&14_i64.to_le_bytes());
social_claim_authority_data.extend_from_slice(&[3_u8; 32]);
let social_claim_authority_event = decode_synthetic_anchor_event(
social_claim_authority_data,
"set social claim authority event",
);
assert_eq!(
social_claim_authority_event.spec.name,
"SetSocialClaimAuthorityEvent"
);
assert_eq!(
social_claim_authority_event.discriminator_hex,
"3c767f84ef34fe0e"
);
assert_eq!(
social_claim_authority_event.fields_json["social_claim_authority"],
serde_json::json!(bs58::encode([3_u8; 32]).into_string())
);
}
#[test]
fn ignores_truncated_known_instruction_payload() {
let mut data = std::vec::Vec::new();
data.extend_from_slice(&super::PUMP_FEES_GET_FEES_DISCRIMINATOR);
let encoded = bs58::encode(data).into_string();
let data_json = serde_json::json!(encoded).to_string();
let decoded_result = super::parse_pump_fees_instruction_data(Some(&data_json));
match decoded_result {
Ok(None) => {},
Ok(Some(decoded)) => panic!("unexpected decoded truncated instruction: {}", decoded.spec.name),
Err(error) => panic!("truncated instruction should be ignored: {}", error),
}
}
#[test]
fn ignores_truncated_known_anchor_event_payload() {
let data = pump_fees_anchor_event_prefix(
&super::PUMP_FEES_SOCIAL_FEE_PDA_CLAIMED_DISCRIMINATOR,
);
let encoded = {
use base64::Engine as _;
base64::engine::general_purpose::STANDARD.encode(data)
};
let decoded_result = super::decode_pump_fees_anchor_event_from_base64(encoded.as_str());
match decoded_result {
Ok(None) => {},
Ok(Some(decoded)) => panic!("unexpected decoded truncated anchor event: {}", decoded.spec.name),
Err(error) => panic!("truncated anchor event should be ignored: {}", error),
}
}
fn pump_fees_anchor_event_prefix(event_discriminator: &[u8; 8]) -> std::vec::Vec<u8> {
let mut data = std::vec::Vec::new();
data.extend_from_slice(&super::PUMP_FEES_ANCHOR_SELF_CPI_LOG_DISCRIMINATOR);
data.extend_from_slice(event_discriminator);
return data;
}
fn decode_synthetic_anchor_event(
data: std::vec::Vec<u8>,
context: &str,
) -> super::PumpFeesAnchorEventData {
let encoded = {
use base64::Engine as _;
base64::engine::general_purpose::STANDARD.encode(data)
};
let decoded_result = super::decode_pump_fees_anchor_event_from_base64(encoded.as_str());
match decoded_result {
Ok(Some(decoded)) => return decoded,
Ok(None) => panic!("expected decoded {}", context),
Err(error) => panic!("unexpected decode error for {}: {}", context, error),
}
}
}