From e4dc6f731ce0e535bfd898af4be57d55f8e7ef2f Mon Sep 17 00:00:00 2001 From: dougefresh Date: Sat, 25 Oct 2025 17:50:46 +0000 Subject: [PATCH] fix: derive fee account --- .../src/helpers/receive_message_helpers.rs | 74 +++++++++++-------- examples/circle-cctp/src/main.rs | 1 - 2 files changed, 44 insertions(+), 31 deletions(-) diff --git a/encoders/circle-message-transmitter-v2-encoder/src/helpers/receive_message_helpers.rs b/encoders/circle-message-transmitter-v2-encoder/src/helpers/receive_message_helpers.rs index 273a859..6d3d528 100644 --- a/encoders/circle-message-transmitter-v2-encoder/src/helpers/receive_message_helpers.rs +++ b/encoders/circle-message-transmitter-v2-encoder/src/helpers/receive_message_helpers.rs @@ -1,6 +1,6 @@ use { super::FeeRecipientFetcher, - crate::{instructions::receive_message, types::ReceiveMessageParams}, + crate::{TOKEN_MINTER_PROGRAM_ID, instructions::receive_message, types::ReceiveMessageParams}, alloy_primitives::FixedBytes, borsh::BorshDeserialize, nitrogen_instruction_builder::{InstructionBuilder, derive_pda}, @@ -8,6 +8,8 @@ use { solana_pubkey::Pubkey, solana_rpc_client::nonblocking::rpc_client::RpcClient, solana_rpc_client_api::client_error::Result as ClientResult, + std::fmt::{Debug, Display}, + tracing::debug, }; #[async_trait::async_trait] @@ -18,15 +20,18 @@ impl + Send + Sync> FeeRecipientFetcher for T { ) -> ClientResult { let token_messenger_account = Pubkey::find_program_address(&[b"token_messenger"], &super::TOKEN_MINTER_PROGRAM_ID).0; + debug!("lookup up token_messenger_account {token_messenger_account}"); let account_data = self .as_ref() .get_account_data(&token_messenger_account) .await?; - let fee_recipient = TokenMessenger::try_from_slice(&account_data[8..])?.fee_recipient; - Ok(spl_associated_token_account::get_associated_token_address( + let fee_recipient = decode_fee_recipient_account(&account_data)?; + let token_account = spl_associated_token_account::get_associated_token_address( &fee_recipient, circle_usdc_address, - )) + ); + debug!("fee recipient token account {token_account}"); + Ok(token_account) } } @@ -43,28 +48,36 @@ struct TokenMessenger { pub min_fee: u32, } -pub async fn fee_recipient_token_account_internal( - account_data: &[u8], - circle_usdc_address: &Pubkey, -) -> ClientResult { - let fee_recipient = TokenMessenger::try_from_slice(&account_data[8..])?.fee_recipient; - Ok(spl_associated_token_account::get_associated_token_address( - &fee_recipient, - circle_usdc_address, - )) +impl Display for TokenMessenger { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!( + f, + "denylister={},owner={},pending_owner={},message_body_version={},fee_recipient={},\ + min_fee_controller={},min_fee={}", + self.denylister, + self.owner, + self.pending_owner, + self.message_body_version, + self.fee_recipient, + self.min_fee_controller, + self.min_fee + ) + } +} + +#[allow(clippy::result_large_err)] +pub fn decode_fee_recipient_account(account_data: &[u8]) -> ClientResult { + let messenger = TokenMessenger::try_from_slice(&account_data[8..])?; + debug!("TokenMessenger: {messenger}"); + Ok(messenger.fee_recipient) } pub async fn fee_recipient_token_account( rpc: &T, circle_usdc_address: &Pubkey, ) -> ClientResult { - let fee_recipient = rpc - .get_fee_recipient_token_account(circle_usdc_address) - .await?; - Ok(spl_associated_token_account::get_associated_token_address( - &fee_recipient, - circle_usdc_address, - )) + rpc.get_fee_recipient_token_account(circle_usdc_address) + .await } pub fn recv_from_attestation( @@ -92,12 +105,13 @@ pub fn recv_from_attestation( ) } -/// https://github.com/circlefin/solana-cctp-contracts/blob/03f7dec786eb9affa68688954f62917edeed2e35/examples/v2/utilsV2.ts +/// +/// +/// pub fn remaining_accounts( recipient: &Pubkey, remote_domain: String, remote_address: FixedBytes<32>, - token_minter_program: &Pubkey, circle_usdc_address: &Pubkey, fee_recipient_token_account: &Pubkey, ) -> Vec { @@ -105,16 +119,16 @@ pub fn remaining_accounts( spl_associated_token_account::get_associated_token_address(recipient, circle_usdc_address); let remote_address = Pubkey::new_from_array(remote_address.into()); vec![ - derive_pda(&[b"token_messenger"], token_minter_program, true), + derive_pda(&[b"token_messenger"], &TOKEN_MINTER_PROGRAM_ID, true), derive_pda( &[b"remote_token_messenger", remote_domain.as_bytes()], - token_minter_program, + &TOKEN_MINTER_PROGRAM_ID, true, ), - derive_pda(&[b"token_minter"], token_minter_program, false), + derive_pda(&[b"token_minter"], &TOKEN_MINTER_PROGRAM_ID, false), derive_pda( &[b"local_token", circle_usdc_address.as_ref()], - token_minter_program, + &TOKEN_MINTER_PROGRAM_ID, false, ), derive_pda( @@ -123,18 +137,18 @@ pub fn remaining_accounts( remote_domain.as_bytes(), remote_address.as_ref(), ], - token_minter_program, + &TOKEN_MINTER_PROGRAM_ID, true, ), AccountMeta::new(*fee_recipient_token_account, false), AccountMeta::new(user_token_account, false), derive_pda( &[b"custody", circle_usdc_address.as_ref()], - token_minter_program, + &TOKEN_MINTER_PROGRAM_ID, false, ), AccountMeta::new_readonly(spl_token::ID, false), - derive_pda(&[b"__event_authority"], token_minter_program, true), - AccountMeta::new_readonly(*token_minter_program, false), + derive_pda(&[b"__event_authority"], &TOKEN_MINTER_PROGRAM_ID, true), + AccountMeta::new_readonly(TOKEN_MINTER_PROGRAM_ID, false), ] } diff --git a/examples/circle-cctp/src/main.rs b/examples/circle-cctp/src/main.rs index 4032c37..18b9569 100644 --- a/examples/circle-cctp/src/main.rs +++ b/examples/circle-cctp/src/main.rs @@ -280,7 +280,6 @@ pub async fn main() -> Result<()> { &owner.pubkey(), "6".to_string(), // base sepolia usdc_evm_addr.into_word(), - &TOKEN_MINTER_PROGRAM_ID, &SOLANA_USDC_ADDRESS, &fee_recipient, );