diff --git a/solana/bridge/program/src/api/governance.rs b/solana/bridge/program/src/api/governance.rs index e434b405..fffea82d 100644 --- a/solana/bridge/program/src/api/governance.rs +++ b/solana/bridge/program/src/api/governance.rs @@ -220,10 +220,11 @@ pub fn transfer_fees( accs.recipient.key, accs.vaa.amount.as_u64(), ); - let seeds = accs.fee_collector.self_seeds(None); - let s: Vec<&[u8]> = seeds.iter().map(|item| item.as_slice()).collect(); - let seed_slice = s.as_slice(); - invoke_signed(&transfer_ix, ctx.accounts, &[seed_slice])?; + + let seeds = accs.fee_collector.self_bumped_seeds(None, ctx.program_id); + let seeds: Vec<&[u8]> = seeds.iter().map(|item| item.as_slice()).collect(); + let seeds = seeds.as_slice(); + invoke_signed(&transfer_ix, ctx.accounts, &[seeds])?; Ok(()) } diff --git a/solana/bridge/program/src/instructions.rs b/solana/bridge/program/src/instructions.rs index 17a403d7..2ef7e63b 100644 --- a/solana/bridge/program/src/instructions.rs +++ b/solana/bridge/program/src/instructions.rs @@ -330,14 +330,20 @@ pub fn set_fees( } } -pub fn transfer_fees(program_id: Pubkey, payer: Pubkey, recipient: Pubkey) -> Instruction { +pub fn transfer_fees( + program_id: Pubkey, + payer: Pubkey, + message: Pubkey, + emitter: Pubkey, + sequence: u64, + recipient: Pubkey, +) -> Instruction { let bridge = Bridge::<'_, { AccountState::Uninitialized }>::key(None, &program_id); - let payload_message = Pubkey::new_unique(); let claim = Claim::<'_, { AccountState::Uninitialized }>::key( &ClaimDerivationData { - emitter_address: [0u8; 32], + emitter_address: emitter.to_bytes(), emitter_chain: CHAIN_ID_SOLANA, - sequence: 0, + sequence, }, &program_id, ); @@ -350,7 +356,7 @@ pub fn transfer_fees(program_id: Pubkey, payer: Pubkey, recipient: Pubkey) -> In accounts: vec![ AccountMeta::new(payer, true), AccountMeta::new(bridge, false), - AccountMeta::new(payload_message, false), + AccountMeta::new(message, false), AccountMeta::new(claim, false), AccountMeta::new(fee_collector, false), AccountMeta::new(recipient, false), diff --git a/solana/bridge/program/src/types.rs b/solana/bridge/program/src/types.rs index a17d3979..df98f1d4 100644 --- a/solana/bridge/program/src/types.rs +++ b/solana/bridge/program/src/types.rs @@ -355,6 +355,17 @@ pub struct GovernancePayloadTransferFees { pub to: ForeignAddress, } +impl SerializePayload for GovernancePayloadTransferFees { + fn serialize(&self, v: &mut W) -> std::result::Result<(), SolitaireError> { + use byteorder::WriteBytesExt; + let mut amount_data = [0u8; 32]; + self.amount.to_big_endian(&mut amount_data); + v.write(&amount_data)?; + v.write(&self.to); + Ok(()) + } +} + impl DeserializePayload for GovernancePayloadTransferFees where Self: DeserializeGovernancePayload, diff --git a/solana/bridge/program/tests/common.rs b/solana/bridge/program/tests/common.rs index 4b89a44e..b8768942 100644 --- a/solana/bridge/program/tests/common.rs +++ b/solana/bridge/program/tests/common.rs @@ -125,7 +125,7 @@ mod helpers { let payer = read_keypair_file(payer).unwrap(); let rpc = RpcClient::new(rpc_address); let program = env::var("BRIDGE_PROGRAM") - .unwrap_or("6mFKdAtUBVbsQ5dgvBrUkn1Pixb7BMTUtVKj4dpwrmQs".to_string()) + .unwrap_or("Bridge1p5gheXUvJ6jGWGeCsgPKgnE3YgdGKRVCMY9o".to_string()) .parse::() .unwrap(); (payer, rpc, program) @@ -249,6 +249,7 @@ mod helpers { *program, payer.pubkey(), 500, + 500, 2_000_000_000, initial_guardians, ) @@ -417,7 +418,10 @@ mod helpers { client: &RpcClient, program: &Pubkey, payer: &Keypair, - recipient: &Pubkey, + message: Pubkey, + emitter: Pubkey, + sequence: u64, + recipient: Pubkey, ) -> Result { execute( client, @@ -426,7 +430,10 @@ mod helpers { &[instructions::transfer_fees( *program, payer.pubkey(), - *recipient, + message, + emitter, + sequence, + recipient, )], ) } diff --git a/solana/bridge/program/tests/integration.rs b/solana/bridge/program/tests/integration.rs index c86e8903..e861ddd8 100644 --- a/solana/bridge/program/tests/integration.rs +++ b/solana/bridge/program/tests/integration.rs @@ -56,6 +56,7 @@ use bridge::{ BridgeConfig, GovernancePayloadGuardianSetChange, GovernancePayloadSetMessageFee, + GovernancePayloadTransferFees, PostedMessage, PostedMessageData, SequenceTracker, @@ -99,6 +100,7 @@ fn run_integration_tests() { test_guardian_set_change(&mut context); test_guardian_set_change_fails(&mut context); test_set_fees(&mut context); + test_transfer_fees(&mut context); } fn test_bridge_messages(context: &mut Context) { @@ -281,6 +283,7 @@ fn test_set_fees(context: &mut Context) { false, ) .unwrap(); + let (vaa, body, body_hash) = common::generate_vaa(&emitter, message.clone(), nonce, 1); common::verify_signatures(client, program, payer, body, body_hash, &context.secret, 1).unwrap(); common::post_vaa(client, program, payer, vaa).unwrap(); @@ -318,3 +321,43 @@ fn test_set_fees(context: &mut Context) { ) .unwrap(); } + +fn test_transfer_fees(context: &mut Context) { + // Initialize a wormhole bridge on Solana to test with. + let (ref payer, ref client, ref program) = common::setup(); + let emitter = Keypair::from_bytes(&GOV_KEY).unwrap(); + + let nonce = 12401; + let message = GovernancePayloadTransferFees { + amount: 100.into(), + to: payer.pubkey().to_bytes(), + } + .try_to_vec() + .unwrap(); + + let message_key = common::post_message( + client, + program, + payer, + &emitter, + nonce, + message.clone(), + 10_000, + false, + ) + .unwrap(); + + let (vaa, body, body_hash) = common::generate_vaa(&emitter, message.clone(), nonce, 1); + common::verify_signatures(client, program, payer, body, body_hash, &context.secret, 1).unwrap(); + common::post_vaa(client, program, payer, vaa).unwrap(); + common::transfer_fees( + client, + program, + payer, + message_key, + emitter.pubkey(), + 4, + payer.pubkey(), + ) + .unwrap(); +}