diff --git a/crates/solana-cli/CHANGELOG.md b/crates/solana-cli/CHANGELOG.md index c252966c..1c303a00 100644 --- a/crates/solana-cli/CHANGELOG.md +++ b/crates/solana-cli/CHANGELOG.md @@ -7,6 +7,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +- `shreds payments`: keep reading leftover fund-seat transactions after the SDK drops that instruction (malbeclabs/infra#2411) - `shreds pay`: remove the command. `shreds withdraw`, `list`, `payments`, and `price` stay (malbeclabs/infra#2410) - `shreds`: collapse `pay`'s `SLOT_DURATION_SECS` and `prepare-offchain-message`'s `SLOT_DURATION_MS` into one `NOMINAL_SLOT_DURATION` at 350ms, matching mainnet-beta from epoch 1020 (2026-08-21). Deliberately cluster-independent, because a `~` prefixed estimate and a deadline slot the CLI and operator must both compute want reproducibility over accuracy. `--valid-for 1h` now resolves to 10,285 slots rather than 9,000, and the epoch-remaining estimates shrink by an eighth. Testnet runs at 200ms, so its estimates stay wrong in the other direction, and SIMD-0525 will need one more bump here (malbeclabs/infra#2317) - `shreds validator-client-rewards`: read the `ValidatorClientRewards` account through the SDK's zero-copy mirror instead of the hand-written byte-offset parser. Every subcommand now requires at least 184 bytes of account data rather than 116 diff --git a/crates/solana-cli/src/command/shreds/payments.rs b/crates/solana-cli/src/command/shreds/payments.rs index 1cf25fce..3cc888ff 100644 --- a/crates/solana-cli/src/command/shreds/payments.rs +++ b/crates/solana-cli/src/command/shreds/payments.rs @@ -83,6 +83,15 @@ impl std::fmt::Display for EventType { } } +const LEGACY_FUND_PAYMENT_ESCROW_USDC: [u8; 8] = [111, 6, 96, 2, 121, 92, 68, 147]; + +fn parse_legacy_fund_payment_escrow_usdc(data: &[u8]) -> Option { + if data.len() < 16 || data[..8] != LEGACY_FUND_PAYMENT_ESCROW_USDC { + return None; + } + Some(u64::from_le_bytes(data[8..16].try_into().ok()?)) +} + impl PaymentsCommand { pub async fn execute( self, @@ -194,14 +203,16 @@ impl PaymentsCommand { continue; } + if let Some(amount) = parse_legacy_fund_payment_escrow_usdc(&ix.data) { + events.push(PaymentEvent { + event_type: EventType::Funded, + amount_micro: amount as i64, + block_time: tx_response.block_time, + }); + continue; + } + match ShredSubscriptionInstructionData::try_from_slice(&ix.data) { - Ok(ShredSubscriptionInstructionData::FundPaymentEscrowUsdc(amount)) => { - events.push(PaymentEvent { - event_type: EventType::Funded, - amount_micro: amount as i64, - block_time: tx_response.block_time, - }); - } // TODO: ClosePaymentEscrow (withdrawal) — the actual // refunded amount is in the tx log message "Withdrew {} // USDC from payment escrow to refund account". Parse that diff --git a/crates/solana-sdk/src/shred_subscription/instruction/account.rs b/crates/solana-sdk/src/shred_subscription/instruction/account.rs index d16c13dc..fa6e2f38 100644 --- a/crates/solana-sdk/src/shred_subscription/instruction/account.rs +++ b/crates/solana-sdk/src/shred_subscription/instruction/account.rs @@ -366,71 +366,6 @@ impl From for Vec { } } -/// Accounts for the `FundPaymentEscrowUsdc` instruction (10 accounts). -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct FundPaymentEscrowUsdcAccounts { - pub program_config_key: Pubkey, - pub execution_controller_key: Pubkey, - pub metro_history_key: Pubkey, - pub device_history_key: Pubkey, - pub client_seat_key: Pubkey, - pub payment_escrow_key: Pubkey, - pub device_history_usdc_token_account_key: Pubkey, - pub source_usdc_token_account_key: Pubkey, - pub transfer_authority_key: Pubkey, -} - -impl FundPaymentEscrowUsdcAccounts { - pub fn new( - exchange_key: &Pubkey, - device_key: &Pubkey, - client_ip_bits: u32, - withdraw_authority_key: &Pubkey, - usdc_mint_key: &Pubkey, - source_usdc_token_account_key: &Pubkey, - transfer_authority_key: &Pubkey, - ) -> Self { - let client_seat_key = state::find_client_seat_address(device_key, client_ip_bits).0; - let device_history_key = state::find_device_history_address(device_key).0; - Self { - program_config_key: state::find_program_config_address().0, - execution_controller_key: state::find_execution_controller_address().0, - metro_history_key: state::find_metro_history_address(exchange_key).0, - device_history_key, - client_seat_key, - payment_escrow_key: state::find_payment_escrow_address( - &client_seat_key, - withdraw_authority_key, - ) - .0, - device_history_usdc_token_account_key: state::find_token_pda_address( - &device_history_key, - usdc_mint_key, - ) - .0, - source_usdc_token_account_key: *source_usdc_token_account_key, - transfer_authority_key: *transfer_authority_key, - } - } -} - -impl From for Vec { - fn from(accounts: FundPaymentEscrowUsdcAccounts) -> Self { - vec![ - AccountMeta::new_readonly(accounts.program_config_key, false), - AccountMeta::new(accounts.execution_controller_key, false), - AccountMeta::new_readonly(accounts.metro_history_key, false), - AccountMeta::new_readonly(accounts.device_history_key, false), - AccountMeta::new(accounts.client_seat_key, false), - AccountMeta::new(accounts.payment_escrow_key, false), - AccountMeta::new(accounts.device_history_usdc_token_account_key, false), - AccountMeta::new(accounts.source_usdc_token_account_key, false), - AccountMeta::new_readonly(accounts.transfer_authority_key, true), - AccountMeta::new_readonly(spl_token_interface::ID, false), - ] - } -} - /// Accounts for the `InitializeClaimHolding` instruction (6 accounts). #[derive(Debug, Clone, PartialEq, Eq)] pub struct InitializeClaimHoldingAccounts { diff --git a/crates/solana-sdk/src/shred_subscription/instruction/mod.rs b/crates/solana-sdk/src/shred_subscription/instruction/mod.rs index 82a613f7..bb92eeaa 100644 --- a/crates/solana-sdk/src/shred_subscription/instruction/mod.rs +++ b/crates/solana-sdk/src/shred_subscription/instruction/mod.rs @@ -34,8 +34,6 @@ pub enum ShredSubscriptionInstructionData { InitializePaymentEscrow, /// Close a payment escrow and refund any remaining USDC. ClosePaymentEscrow, - /// Fund a payment escrow with USDC. - FundPaymentEscrowUsdc(u64), /// Request instant allocation for a funded seat (skips auction settlement). RequestInstantSeatAllocation, /// Request instant seat withdrawal. @@ -88,8 +86,6 @@ impl ShredSubscriptionInstructionData { Discriminator::new_sha2(b"dz::ix::initialize_payment_escrow"); pub const CLOSE_PAYMENT_ESCROW: Discriminator = Discriminator::new_sha2(b"dz::ix::close_payment_escrow"); - pub const FUND_PAYMENT_ESCROW_USDC: Discriminator = - Discriminator::new_sha2(b"dz::ix::fund_payment_escrow_usdc"); pub const REQUEST_INSTANT_SEAT_ALLOCATION: Discriminator = Discriminator::new_sha2(b"dz::ix::request_instant_seat_allocation"); pub const REQUEST_INSTANT_SEAT_WITHDRAWAL: Discriminator = @@ -121,10 +117,6 @@ impl BorshSerialize for ShredSubscriptionInstructionData { } Self::InitializePaymentEscrow => Self::INITIALIZE_PAYMENT_ESCROW.serialize(writer), Self::ClosePaymentEscrow => Self::CLOSE_PAYMENT_ESCROW.serialize(writer), - Self::FundPaymentEscrowUsdc(amount) => { - Self::FUND_PAYMENT_ESCROW_USDC.serialize(writer)?; - amount.serialize(writer) - } Self::RequestInstantSeatAllocation => { Self::REQUEST_INSTANT_SEAT_ALLOCATION.serialize(writer) } @@ -189,10 +181,6 @@ impl BorshDeserialize for ShredSubscriptionInstructionData { } Self::INITIALIZE_PAYMENT_ESCROW => Ok(Self::InitializePaymentEscrow), Self::CLOSE_PAYMENT_ESCROW => Ok(Self::ClosePaymentEscrow), - Self::FUND_PAYMENT_ESCROW_USDC => { - let amount = u64::deserialize_reader(reader)?; - Ok(Self::FundPaymentEscrowUsdc(amount)) - } Self::REQUEST_INSTANT_SEAT_ALLOCATION => Ok(Self::RequestInstantSeatAllocation), Self::REQUEST_INSTANT_SEAT_WITHDRAWAL => Ok(Self::RequestInstantSeatWithdrawal), Self::REQUEST_PRORATED_INSTANT_SEAT_WITHDRAWAL => {