fix: use fixed-size slices for protocol data parsing

- Improve borsh deserialization safety across all protocol decoders
- Add MarketState support for raydium_amm_v4
- Prevent buffer overflow in data decoding operations
This commit is contained in:
ysq
2025-08-19 17:37:17 +08:00
parent a9ceaa55d3
commit 915209abd8
9 changed files with 50 additions and 18 deletions
+1 -1
View File
@@ -1,6 +1,6 @@
[package]
name = "solana-streamer-sdk"
version = "0.3.3"
version = "0.3.4"
edition = "2021"
authors = ["William <byteblock6@gmail.com>", "sgxiang <sgxiang@gmail.com>", "wei <1415121722@qq.com>"]
repository = "https://github.com/0xfnzero/solana-streamer"
+2 -2
View File
@@ -44,14 +44,14 @@ Add the dependency to your `Cargo.toml`:
```toml
# Add to your Cargo.toml
solana-streamer-sdk = { path = "./solana-streamer", version = "0.3.3" }
solana-streamer-sdk = { path = "./solana-streamer", version = "0.3.4" }
```
### Use crates.io
```toml
# Add to your Cargo.toml
solana-streamer-sdk = "0.3.3"
solana-streamer-sdk = "0.3.4"
```
## Usage Examples
+2 -2
View File
@@ -44,14 +44,14 @@ git clone https://github.com/0xfnzero/solana-streamer
```toml
# 添加到您的 Cargo.toml
solana-streamer-sdk = { path = "./solana-streamer", version = "0.3.3" }
solana-streamer-sdk = { path = "./solana-streamer", version = "0.3.4" }
```
### 使用 crates.io
```toml
# 添加到您的 Cargo.toml
solana-streamer-sdk = "0.3.3"
solana-streamer-sdk = "0.3.4"
```
## 使用示例
@@ -120,7 +120,7 @@ pub fn pool_state_decode(data: &[u8]) -> Option<PoolState> {
if data.len() < POOL_STATE_SIZE {
return None;
}
borsh::from_slice::<PoolState>(&data).ok()
borsh::from_slice::<PoolState>(&data[..POOL_STATE_SIZE]).ok()
}
pub fn pool_state_parser(
@@ -168,7 +168,7 @@ pub fn global_config_decode(data: &[u8]) -> Option<GlobalConfig> {
if data.len() < GLOBAL_CONFIG_SIZE {
return None;
}
borsh::from_slice::<GlobalConfig>(&data).ok()
borsh::from_slice::<GlobalConfig>(&data[..GLOBAL_CONFIG_SIZE]).ok()
}
pub fn global_config_parser(
@@ -211,7 +211,7 @@ pub fn platform_config_decode(data: &[u8]) -> Option<PlatformConfig> {
if data.len() < PLATFORM_CONFIG_SIZE {
return None;
}
borsh::from_slice::<PlatformConfig>(&data).ok()
borsh::from_slice::<PlatformConfig>(&data[..PLATFORM_CONFIG_SIZE]).ok()
}
pub fn platform_config_parser(
@@ -28,7 +28,7 @@ pub fn bonding_curve_decode(data: &[u8]) -> Option<BondingCurve> {
if data.len() < BONDING_CURVE_SIZE {
return None;
}
borsh::from_slice::<BondingCurve>(&data).ok()
borsh::from_slice::<BondingCurve>(&data[..BONDING_CURVE_SIZE]).ok()
}
pub fn bonding_curve_parser(
@@ -75,7 +75,7 @@ pub fn global_decode(data: &[u8]) -> Option<Global> {
if data.len() < GLOBAL_SIZE {
return None;
}
borsh::from_slice::<Global>(&data).ok()
borsh::from_slice::<Global>(&data[..GLOBAL_SIZE]).ok()
}
pub fn global_parser(
@@ -30,7 +30,7 @@ pub fn global_config_decode(data: &[u8]) -> Option<GlobalConfig> {
if data.len() < GLOBAL_CONFIG_SIZE {
return None;
}
borsh::from_slice::<GlobalConfig>(&data).ok()
borsh::from_slice::<GlobalConfig>(&data[..GLOBAL_CONFIG_SIZE]).ok()
}
pub fn global_config_parser(
@@ -72,7 +72,7 @@ pub fn pool_decode(data: &[u8]) -> Option<Pool> {
if data.len() < POOL_SIZE {
return None;
}
borsh::from_slice::<Pool>(&data).ok()
borsh::from_slice::<Pool>(&data[..POOL_SIZE]).ok()
}
pub fn pool_parser(
@@ -80,7 +80,7 @@ pub struct AmmInfo {
pub const AMM_INFO_SIZE: usize = 752;
pub fn amm_info_decode(data: &[u8]) -> Option<AmmInfo> {
borsh::from_slice::<AmmInfo>(&data).ok()
borsh::from_slice::<AmmInfo>(&data[..AMM_INFO_SIZE]).ok()
}
pub fn amm_info_parser(
@@ -104,3 +104,35 @@ pub fn amm_info_parser(
None
}
}
#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize, BorshDeserialize)]
pub struct MarketState {
pub padding: [u8; 5],
pub account_flags: u64,
pub own_address: Pubkey,
pub vault_signer_nonce: u64,
pub coin_mint: Pubkey,
pub pc_mint: Pubkey,
pub serum_coin_vault_account: Pubkey,
pub coin_deposits_total: u64,
pub coin_fees_accrued: u64,
pub serum_pc_vault_account: Pubkey,
pub pc_deposits_total: u64,
pub pc_fees_accrued: u64,
pub pc_dust_threshold: u64,
pub request_queue: Pubkey,
pub serum_event_queue: Pubkey,
pub serum_bids: Pubkey,
pub serum_asks: Pubkey,
pub coin_lot_size: u64,
pub pc_lot_size: u64,
pub fee_rate_bps: u64,
pub referrer_rebate_accrued: u64,
pub padding2: [u8; 7],
}
pub const MARKET_STATE_SIZE: usize = 388;
pub fn market_state_decode(data: &[u8]) -> Option<MarketState> {
borsh::from_slice::<MarketState>(&data[..MARKET_STATE_SIZE]).ok()
}
@@ -31,7 +31,7 @@ pub struct AmmConfig {
pub const AMM_CONFIG_SIZE: usize = 1 + 2 + 32 + 4 * 2 + 2 + 4 * 2 + 32 + 8 * 3;
pub fn amm_config_decode(data: &[u8]) -> Option<AmmConfig> {
borsh::from_slice::<AmmConfig>(&data).ok()
borsh::from_slice::<AmmConfig>(&data[..AMM_CONFIG_SIZE]).ok()
}
pub fn amm_config_parser(
@@ -116,7 +116,7 @@ pub struct PoolState {
pub const POOL_STATE_SIZE: usize = 1536;
pub fn pool_state_decode(data: &[u8]) -> Option<PoolState> {
borsh::from_slice::<PoolState>(&data).ok()
borsh::from_slice::<PoolState>(&data[..POOL_STATE_SIZE]).ok()
}
pub fn pool_state_parser(
@@ -194,7 +194,7 @@ impl Default for TickArrayState {
pub const TICK_ARRAY_STATE_SIZE: usize = 10232;
pub fn tick_array_state_decode(data: &[u8]) -> Option<TickArrayState> {
borsh::from_slice::<TickArrayState>(&data).ok()
borsh::from_slice::<TickArrayState>(&data[..TICK_ARRAY_STATE_SIZE]).ok()
}
pub fn tick_array_state_parser(
@@ -30,7 +30,7 @@ pub struct AmmConfig {
pub const AMM_CONFIG_SIZE: usize = 228;
pub fn amm_config_decode(data: &[u8]) -> Option<AmmConfig> {
borsh::from_slice::<AmmConfig>(&data).ok()
borsh::from_slice::<AmmConfig>(&data[..AMM_CONFIG_SIZE]).ok()
}
pub fn amm_config_parser(
@@ -85,7 +85,7 @@ pub struct PoolState {
pub const POOL_STATE_SIZE: usize = 629;
pub fn pool_state_decode(data: &[u8]) -> Option<PoolState> {
borsh::from_slice::<PoolState>(&data).ok()
borsh::from_slice::<PoolState>(&data[..POOL_STATE_SIZE]).ok()
}
pub fn pool_state_parser(