From cc9cc2786a4e3b624bbd175a35a9c57a4e2a3880 Mon Sep 17 00:00:00 2001 From: dhruvja Date: Tue, 31 Oct 2023 14:54:26 +0100 Subject: [PATCH 01/57] added accounts in the storage for transfers --- .../programs/solana-ibc/src/client_state.rs | 10 +++++----- .../programs/solana-ibc/src/execution_context.rs | 12 ++++++------ solana/solana-ibc/programs/solana-ibc/src/lib.rs | 9 +++++---- .../programs/solana-ibc/src/transfer/impls.rs | 13 +++++++------ .../programs/solana-ibc/src/transfer/mod.rs | 2 +- .../programs/solana-ibc/src/validation_context.rs | 6 +++--- 6 files changed, 27 insertions(+), 25 deletions(-) diff --git a/solana/solana-ibc/programs/solana-ibc/src/client_state.rs b/solana/solana-ibc/programs/solana-ibc/src/client_state.rs index fd43cfca..0d2f3682 100644 --- a/solana/solana-ibc/programs/solana-ibc/src/client_state.rs +++ b/solana/solana-ibc/programs/solana-ibc/src/client_state.rs @@ -84,7 +84,7 @@ impl From for Any { } } -impl ClientStateValidation> for AnyClientState { +impl ClientStateValidation> for AnyClientState { fn verify_client_message( &self, ctx: &IbcStorage, @@ -289,7 +289,7 @@ impl From for AnyClientState { fn from(value: MockClientState) -> Self { AnyClientState::Mock(value) } } -impl ClientStateExecution> for AnyClientState { +impl ClientStateExecution> for AnyClientState { fn initialise( &self, ctx: &mut IbcStorage, @@ -377,7 +377,7 @@ impl ClientStateExecution> for AnyClientState { } } -impl ibc::clients::ics07_tendermint::CommonContext for IbcStorage<'_, '_> { +impl ibc::clients::ics07_tendermint::CommonContext for IbcStorage<'_, '_, '_> { type ConversionError = ClientError; type AnyConsensusState = AnyConsensusState; @@ -416,7 +416,7 @@ impl ibc::clients::ics07_tendermint::CommonContext for IbcStorage<'_, '_> { } #[cfg(any(test, feature = "mocks"))] -impl MockClientContext for IbcStorage<'_, '_> { +impl MockClientContext for IbcStorage<'_, '_, '_> { type ConversionError = ClientError; type AnyConsensusState = AnyConsensusState; @@ -436,7 +436,7 @@ impl MockClientContext for IbcStorage<'_, '_> { } } -impl ibc::clients::ics07_tendermint::ValidationContext for IbcStorage<'_, '_> { +impl ibc::clients::ics07_tendermint::ValidationContext for IbcStorage<'_, '_, '_> { fn next_consensus_state( &self, client_id: &ClientId, diff --git a/solana/solana-ibc/programs/solana-ibc/src/execution_context.rs b/solana/solana-ibc/programs/solana-ibc/src/execution_context.rs index 89698f3f..c72ed668 100644 --- a/solana/solana-ibc/programs/solana-ibc/src/execution_context.rs +++ b/solana/solana-ibc/programs/solana-ibc/src/execution_context.rs @@ -33,7 +33,7 @@ use crate::{ type Result = core::result::Result; -impl ClientExecutionContext for IbcStorage<'_, '_> { +impl ClientExecutionContext for IbcStorage<'_, '_, '_> { type V = Self; // ClientValidationContext type AnyClientState = AnyClientState; type AnyConsensusState = AnyConsensusState; @@ -197,7 +197,7 @@ impl ClientExecutionContext for IbcStorage<'_, '_> { } } -impl ExecutionContext for IbcStorage<'_, '_> { +impl ExecutionContext for IbcStorage<'_, '_, '_> { fn increase_client_counter(&mut self) -> Result { let mut store = self.0.borrow_mut(); store.private.client_counter = @@ -422,7 +422,7 @@ impl ExecutionContext for IbcStorage<'_, '_> { seq: Sequence, ) -> Result { msg!("store_next_sequence_send: path: {path}, seq: {seq}"); - let store: &mut IbcStorageInner<'_, '_> = &mut self.0.borrow_mut(); + let store: &mut IbcStorageInner<'_, '_, '_> = &mut self.0.borrow_mut(); store.store_next_sequence( path.into(), super::SequenceTripleIdx::Send, @@ -436,7 +436,7 @@ impl ExecutionContext for IbcStorage<'_, '_> { seq: Sequence, ) -> Result { msg!("store_next_sequence_recv: path: {path}, seq: {seq}"); - let store: &mut IbcStorageInner<'_, '_> = &mut self.0.borrow_mut(); + let store: &mut IbcStorageInner<'_, '_, '_> = &mut self.0.borrow_mut(); store.store_next_sequence( path.into(), super::SequenceTripleIdx::Recv, @@ -450,7 +450,7 @@ impl ExecutionContext for IbcStorage<'_, '_> { seq: Sequence, ) -> Result { msg!("store_next_sequence_ack: path: {path}, seq: {seq}"); - let store: &mut IbcStorageInner<'_, '_> = &mut self.0.borrow_mut(); + let store: &mut IbcStorageInner<'_, '_, '_> = &mut self.0.borrow_mut(); store.store_next_sequence( path.into(), super::SequenceTripleIdx::Ack, @@ -495,7 +495,7 @@ impl ExecutionContext for IbcStorage<'_, '_> { fn get_client_execution_context(&mut self) -> &mut Self::E { self } } -impl IbcStorageInner<'_, '_> { +impl IbcStorageInner<'_, '_, '_> { fn store_next_sequence( &mut self, path: crate::trie_key::SequencePath<'_>, diff --git a/solana/solana-ibc/programs/solana-ibc/src/lib.rs b/solana/solana-ibc/programs/solana-ibc/src/lib.rs index 227d7540..d45f1601 100644 --- a/solana/solana-ibc/programs/solana-ibc/src/lib.rs +++ b/solana/solana-ibc/programs/solana-ibc/src/lib.rs @@ -52,7 +52,7 @@ pub mod solana_ibc { solana_trie::AccountTrie::new(account.try_borrow_mut_data()?) .ok_or(ProgramError::InvalidAccountData)?; - let inner = IbcStorageInner { private, provable }; + let inner = IbcStorageInner { private, provable, accounts: ctx.remaining_accounts.to_vec() }; let mut store = IbcStorage(Rc::new(RefCell::new(inner))); let mut router = store.clone(); @@ -229,16 +229,17 @@ pub struct PrivateStorage { /// All the structs from IBC are stored as String since they dont implement AnchorSerialize and AnchorDeserialize #[derive(Debug)] -pub struct IbcStorageInner<'a, 'b> { +pub struct IbcStorageInner<'a, 'b, 'c> { pub private: &'a mut PrivateStorage, pub provable: solana_trie::AccountTrie>, + pub accounts: Vec> } #[derive(Debug, Clone)] -struct IbcStorage<'a, 'b>(Rc>>); +struct IbcStorage<'a, 'b, 'c>(Rc>>); -impl Router for IbcStorage<'_, '_> { +impl Router for IbcStorage<'_, '_, '_> { // fn get_route(&self, module_id: &ModuleId) -> Option<&dyn Module> { let module_id = core::borrow::Borrow::borrow(module_id); diff --git a/solana/solana-ibc/programs/solana-ibc/src/transfer/impls.rs b/solana/solana-ibc/programs/solana-ibc/src/transfer/impls.rs index 4c4e13ab..258027ce 100644 --- a/solana/solana-ibc/programs/solana-ibc/src/transfer/impls.rs +++ b/solana/solana-ibc/programs/solana-ibc/src/transfer/impls.rs @@ -1,3 +1,4 @@ +use anchor_lang::prelude::Pubkey; use anchor_lang::solana_program::msg; use ibc::applications::transfer::context::{ TokenTransferExecutionContext, TokenTransferValidationContext, @@ -8,9 +9,9 @@ use ibc::core::ics24_host::identifier::{ChannelId, PortId}; use ibc::Signer; // use crate::module_holder::IbcStorage<'_,'_>; -use crate::IbcStorage; +use crate::{IbcStorage, id}; -impl TokenTransferExecutionContext for IbcStorage<'_, '_> { +impl TokenTransferExecutionContext for IbcStorage<'_, '_, '_> { fn send_coins_execute( &mut self, _from: &Self::AccountId, @@ -56,7 +57,7 @@ impl TokenTransferExecutionContext for IbcStorage<'_, '_> { } } -impl TokenTransferValidationContext for IbcStorage<'_, '_> { +impl TokenTransferValidationContext for IbcStorage<'_, '_, '_> { type AccountId = Signer; fn get_port(&self) -> Result { @@ -68,9 +69,9 @@ impl TokenTransferValidationContext for IbcStorage<'_, '_> { port_id: &PortId, channel_id: &ChannelId, ) -> Result { - let escrow_account = - format!("{}.ef.{}", channel_id.as_str(), port_id.as_str(),); - Ok(Signer::from(escrow_account)) + let seeds = [port_id.as_bytes().as_ref(), channel_id.as_bytes().as_ref()]; + let escrow_account = Pubkey::find_program_address(&seeds, &id()); + Ok(Signer::from(escrow_account.0.to_string())) } fn can_send_coins(&self) -> Result<(), TokenTransferError> { diff --git a/solana/solana-ibc/programs/solana-ibc/src/transfer/mod.rs b/solana/solana-ibc/programs/solana-ibc/src/transfer/mod.rs index 0306825e..656d3d10 100644 --- a/solana/solana-ibc/programs/solana-ibc/src/transfer/mod.rs +++ b/solana/solana-ibc/programs/solana-ibc/src/transfer/mod.rs @@ -17,7 +17,7 @@ use crate::IbcStorage; mod impls; -impl Module for IbcStorage<'_, '_> { +impl Module for IbcStorage<'_, '_, '_> { fn on_chan_open_init_validate( &self, order: Order, diff --git a/solana/solana-ibc/programs/solana-ibc/src/validation_context.rs b/solana/solana-ibc/programs/solana-ibc/src/validation_context.rs index 6e2425c6..93adc673 100644 --- a/solana/solana-ibc/programs/solana-ibc/src/validation_context.rs +++ b/solana/solana-ibc/programs/solana-ibc/src/validation_context.rs @@ -25,7 +25,7 @@ use crate::client_state::AnyClientState; use crate::consensus_state::AnyConsensusState; use crate::IbcStorage; -impl ValidationContext for IbcStorage<'_, '_> { +impl ValidationContext for IbcStorage<'_, '_, '_> { type V = Self; // ClientValidationContext type E = Self; // ClientExecutionContext type AnyConsensusState = AnyConsensusState; @@ -346,7 +346,7 @@ impl ValidationContext for IbcStorage<'_, '_> { } } -impl ibc::core::ics02_client::ClientValidationContext for IbcStorage<'_, '_> { +impl ibc::core::ics02_client::ClientValidationContext for IbcStorage<'_, '_, '_> { fn client_update_time( &self, client_id: &ClientId, @@ -402,7 +402,7 @@ impl ibc::core::ics02_client::ClientValidationContext for IbcStorage<'_, '_> { } } -impl IbcStorage<'_, '_> { +impl IbcStorage<'_, '_, '_> { fn get_next_sequence( &self, path: crate::trie_key::SequencePath<'_>, From 24f16d85af63a4d4defa6d7429e640c5fa835fb9 Mon Sep 17 00:00:00 2001 From: dhruvja Date: Wed, 1 Nov 2023 15:44:56 +0100 Subject: [PATCH 02/57] added mint, burn and send methods --- Cargo.toml | 2 + .../solana-ibc/programs/solana-ibc/Cargo.toml | 2 + .../programs/solana-ibc/src/client_state.rs | 14 +- .../solana-ibc/src/execution_context.rs | 15 +- .../solana-ibc/programs/solana-ibc/src/lib.rs | 18 +- .../programs/solana-ibc/src/transfer/impls.rs | 197 ++++++++++++++++-- .../programs/solana-ibc/src/transfer/mod.rs | 2 +- .../solana-ibc/src/validation_context.rs | 8 +- 8 files changed, 221 insertions(+), 37 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index c3673e90..d7741c8e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -24,6 +24,8 @@ codegen-units = 1 [workspace.dependencies] anchor-lang = {version = "0.28.0", features = ["init-if-needed"]} +anchor-spl = "0.28.0" +uint = "0.9.5" base64 = { version = "0.21", default-features = false, features = ["alloc"] } borsh = { version = "0.10.3", default-features = false } derive_more = "0.99.17" diff --git a/solana/solana-ibc/programs/solana-ibc/Cargo.toml b/solana/solana-ibc/programs/solana-ibc/Cargo.toml index 004c30fa..c9dfc296 100644 --- a/solana/solana-ibc/programs/solana-ibc/Cargo.toml +++ b/solana/solana-ibc/programs/solana-ibc/Cargo.toml @@ -17,6 +17,8 @@ mocks = ["ibc/mocks", "ibc/std"] [dependencies] anchor-lang.workspace = true +anchor-spl.workspace = true +uint.workspace = true ibc.workspace = true ibc-proto.workspace = true serde.workspace = true diff --git a/solana/solana-ibc/programs/solana-ibc/src/client_state.rs b/solana/solana-ibc/programs/solana-ibc/src/client_state.rs index 0d2f3682..8eb98d9a 100644 --- a/solana/solana-ibc/programs/solana-ibc/src/client_state.rs +++ b/solana/solana-ibc/programs/solana-ibc/src/client_state.rs @@ -84,7 +84,7 @@ impl From for Any { } } -impl ClientStateValidation> for AnyClientState { +impl ClientStateValidation> for AnyClientState { fn verify_client_message( &self, ctx: &IbcStorage, @@ -289,7 +289,7 @@ impl From for AnyClientState { fn from(value: MockClientState) -> Self { AnyClientState::Mock(value) } } -impl ClientStateExecution> for AnyClientState { +impl ClientStateExecution> for AnyClientState { fn initialise( &self, ctx: &mut IbcStorage, @@ -377,7 +377,9 @@ impl ClientStateExecution> for AnyClientState { } } -impl ibc::clients::ics07_tendermint::CommonContext for IbcStorage<'_, '_, '_> { +impl ibc::clients::ics07_tendermint::CommonContext + for IbcStorage<'_, '_, '_, '_> +{ type ConversionError = ClientError; type AnyConsensusState = AnyConsensusState; @@ -416,7 +418,7 @@ impl ibc::clients::ics07_tendermint::CommonContext for IbcStorage<'_, '_, '_> { } #[cfg(any(test, feature = "mocks"))] -impl MockClientContext for IbcStorage<'_, '_, '_> { +impl MockClientContext for IbcStorage<'_, '_, '_, '_> { type ConversionError = ClientError; type AnyConsensusState = AnyConsensusState; @@ -436,7 +438,9 @@ impl MockClientContext for IbcStorage<'_, '_, '_> { } } -impl ibc::clients::ics07_tendermint::ValidationContext for IbcStorage<'_, '_, '_> { +impl ibc::clients::ics07_tendermint::ValidationContext + for IbcStorage<'_, '_, '_, '_> +{ fn next_consensus_state( &self, client_id: &ClientId, diff --git a/solana/solana-ibc/programs/solana-ibc/src/execution_context.rs b/solana/solana-ibc/programs/solana-ibc/src/execution_context.rs index c72ed668..c4de5c4f 100644 --- a/solana/solana-ibc/programs/solana-ibc/src/execution_context.rs +++ b/solana/solana-ibc/programs/solana-ibc/src/execution_context.rs @@ -33,7 +33,7 @@ use crate::{ type Result = core::result::Result; -impl ClientExecutionContext for IbcStorage<'_, '_, '_> { +impl ClientExecutionContext for IbcStorage<'_, '_, '_, '_> { type V = Self; // ClientValidationContext type AnyClientState = AnyClientState; type AnyConsensusState = AnyConsensusState; @@ -197,7 +197,7 @@ impl ClientExecutionContext for IbcStorage<'_, '_, '_> { } } -impl ExecutionContext for IbcStorage<'_, '_, '_> { +impl ExecutionContext for IbcStorage<'_, '_, '_, '_> { fn increase_client_counter(&mut self) -> Result { let mut store = self.0.borrow_mut(); store.private.client_counter = @@ -422,7 +422,8 @@ impl ExecutionContext for IbcStorage<'_, '_, '_> { seq: Sequence, ) -> Result { msg!("store_next_sequence_send: path: {path}, seq: {seq}"); - let store: &mut IbcStorageInner<'_, '_, '_> = &mut self.0.borrow_mut(); + let store: &mut IbcStorageInner<'_, '_, '_, '_> = + &mut self.0.borrow_mut(); store.store_next_sequence( path.into(), super::SequenceTripleIdx::Send, @@ -436,7 +437,8 @@ impl ExecutionContext for IbcStorage<'_, '_, '_> { seq: Sequence, ) -> Result { msg!("store_next_sequence_recv: path: {path}, seq: {seq}"); - let store: &mut IbcStorageInner<'_, '_, '_> = &mut self.0.borrow_mut(); + let store: &mut IbcStorageInner<'_, '_, '_, '_> = + &mut self.0.borrow_mut(); store.store_next_sequence( path.into(), super::SequenceTripleIdx::Recv, @@ -450,7 +452,8 @@ impl ExecutionContext for IbcStorage<'_, '_, '_> { seq: Sequence, ) -> Result { msg!("store_next_sequence_ack: path: {path}, seq: {seq}"); - let store: &mut IbcStorageInner<'_, '_, '_> = &mut self.0.borrow_mut(); + let store: &mut IbcStorageInner<'_, '_, '_, '_> = + &mut self.0.borrow_mut(); store.store_next_sequence( path.into(), super::SequenceTripleIdx::Ack, @@ -495,7 +498,7 @@ impl ExecutionContext for IbcStorage<'_, '_, '_> { fn get_client_execution_context(&mut self) -> &mut Self::E { self } } -impl IbcStorageInner<'_, '_, '_> { +impl IbcStorageInner<'_, '_, '_, '_> { fn store_next_sequence( &mut self, path: crate::trie_key::SequencePath<'_>, diff --git a/solana/solana-ibc/programs/solana-ibc/src/lib.rs b/solana/solana-ibc/programs/solana-ibc/src/lib.rs index d45f1601..c5110473 100644 --- a/solana/solana-ibc/programs/solana-ibc/src/lib.rs +++ b/solana/solana-ibc/programs/solana-ibc/src/lib.rs @@ -14,6 +14,7 @@ use ibc::core::ics24_host::identifier::PortId; use ibc::core::router::{Module, ModuleId, Router}; const SOLANA_IBC_STORAGE_SEED: &[u8] = b"solana_ibc_storage"; +const MINT_ESCROW_SEED: &[u8] = b"mint_escrow"; const TRIE_SEED: &[u8] = b"trie"; const CONNECTION_ID_PREFIX: &str = "connection-"; const CHANNEL_ID_PREFIX: &str = "channel-"; @@ -51,8 +52,12 @@ pub mod solana_ibc { let provable = solana_trie::AccountTrie::new(account.try_borrow_mut_data()?) .ok_or(ProgramError::InvalidAccountData)?; - - let inner = IbcStorageInner { private, provable, accounts: ctx.remaining_accounts.to_vec() }; + let inner = IbcStorageInner { + private, + provable, + accounts: ctx.remaining_accounts.to_vec(), + signer: ctx.accounts.sender.to_account_info(), + }; let mut store = IbcStorage(Rc::new(RefCell::new(inner))); let mut router = store.clone(); @@ -229,17 +234,18 @@ pub struct PrivateStorage { /// All the structs from IBC are stored as String since they dont implement AnchorSerialize and AnchorDeserialize #[derive(Debug)] -pub struct IbcStorageInner<'a, 'b, 'c> { +pub struct IbcStorageInner<'a, 'b, 'c, 'd> { pub private: &'a mut PrivateStorage, pub provable: solana_trie::AccountTrie>, - pub accounts: Vec> + pub accounts: Vec>, + pub signer: AccountInfo<'d>, } #[derive(Debug, Clone)] -struct IbcStorage<'a, 'b, 'c>(Rc>>); +struct IbcStorage<'a, 'b, 'c, 'd>(Rc>>); -impl Router for IbcStorage<'_, '_, '_> { +impl Router for IbcStorage<'_, '_, '_, '_> { // fn get_route(&self, module_id: &ModuleId) -> Option<&dyn Module> { let module_id = core::borrow::Borrow::borrow(module_id); diff --git a/solana/solana-ibc/programs/solana-ibc/src/transfer/impls.rs b/solana/solana-ibc/programs/solana-ibc/src/transfer/impls.rs index 258027ce..5acec605 100644 --- a/solana/solana-ibc/programs/solana-ibc/src/transfer/impls.rs +++ b/solana/solana-ibc/programs/solana-ibc/src/transfer/impls.rs @@ -1,5 +1,6 @@ -use anchor_lang::prelude::Pubkey; +use anchor_lang::prelude::{CpiContext, Pubkey}; use anchor_lang::solana_program::msg; +use anchor_spl::token::{spl_token, Burn, MintTo, Transfer}; use ibc::applications::transfer::context::{ TokenTransferExecutionContext, TokenTransferValidationContext, }; @@ -7,21 +8,74 @@ use ibc::applications::transfer::error::TokenTransferError; use ibc::applications::transfer::PrefixedCoin; use ibc::core::ics24_host::identifier::{ChannelId, PortId}; use ibc::Signer; +use uint::FromDecStrErr; // use crate::module_holder::IbcStorage<'_,'_>; -use crate::{IbcStorage, id}; +use crate::{id, IbcStorage, MINT_ESCROW_SEED}; -impl TokenTransferExecutionContext for IbcStorage<'_, '_, '_> { +impl TokenTransferExecutionContext for IbcStorage<'_, '_, '_, '_> { fn send_coins_execute( &mut self, - _from: &Self::AccountId, - _to: &Self::AccountId, - _amt: &PrefixedCoin, + from: &Self::AccountId, + to: &Self::AccountId, + amt: &PrefixedCoin, ) -> Result<(), TokenTransferError> { - //let sender_id = from.to_string(); - //let receiver_id = to.to_string(); - //let base_denom = amt.denom.base_denom.to_string(); - todo!() + msg!( + "Sending coins from account {} to account {}, trace path {}, base \ + denom {}", + from, + to, + amt.denom.trace_path, + amt.denom.base_denom + ); + let sender_id = from.to_string(); + let receiver_id = to.to_string(); + let base_denom = amt.denom.base_denom.to_string(); + let amount = amt.amount; + // Since amount is u256 which is array of u64, so if the amount is above u64 max, it means that the amount value at index 0 is max. + if amount[0] == u64::MAX { + return Err(TokenTransferError::InvalidAmount( + FromDecStrErr::InvalidLength, + )); + } + let (_token_mint_key, bump) = + Pubkey::find_program_address(&[base_denom.as_ref()], &id()); + let store = self.0.borrow(); + let sender = store + .accounts + .iter() + .find(|account| account.key.to_string() == sender_id) + .ok_or(TokenTransferError::ParseAccountFailure)?; + let receiver = store + .accounts + .iter() + .find(|account| account.key.to_string() == receiver_id) + .ok_or(TokenTransferError::ParseAccountFailure)?; + let token_program = store + .accounts + .iter() + .find(|&account| { + account.key.to_string() == spl_token::ID.to_string() + }) + .ok_or(TokenTransferError::ParseAccountFailure)?; + + let bump_vector = bump.to_le_bytes(); + let inner = vec![base_denom.as_ref(), bump_vector.as_ref()]; + let outer = vec![inner.as_slice()]; + + // Below is the actual instruction that we are going to send to the Token program. + let transfer_instruction = Transfer { + from: sender.clone(), + to: receiver.clone(), + authority: sender.clone(), + }; + let cpi_ctx = CpiContext::new_with_signer( + token_program.clone(), + transfer_instruction, + outer.as_slice(), //signer PDA + ); + + Ok(anchor_spl::token::transfer(cpi_ctx, amount[0]).unwrap()) } fn mint_coins_execute( @@ -35,9 +89,64 @@ impl TokenTransferExecutionContext for IbcStorage<'_, '_, '_> { amt.denom.trace_path, amt.denom.base_denom ); + let receiver_id = account.to_string(); + let base_denom = amt.denom.base_denom.to_string(); + let amount = amt.amount; + // Since amount is u256 which is array of u64, so if the amount is above u64 max, it means that the amount value at index 0 is max. + if amount[0] == u64::MAX { + return Err(TokenTransferError::InvalidAmount( + FromDecStrErr::InvalidLength, + )); + } + let (token_mint_key, bump) = + Pubkey::find_program_address(&[base_denom.as_ref()], &id()); + let (mint_authority_key, _bump) = + Pubkey::find_program_address(&[MINT_ESCROW_SEED], &id()); + let store = self.0.borrow(); + let receiver = store + .accounts + .iter() + .find(|account| account.key.to_string() == receiver_id) + .ok_or(TokenTransferError::ParseAccountFailure)?; + let token_mint = store + .accounts + .iter() + .find(|account| { + account.key.to_string() == token_mint_key.to_string() + }) + .ok_or(TokenTransferError::ParseAccountFailure)?; + let token_program = store + .accounts + .iter() + .find(|&account| { + account.key.to_string() == spl_token::ID.to_string() + }) + .ok_or(TokenTransferError::ParseAccountFailure)?; + let mint_authority = store + .accounts + .iter() + .find(|&account| { + account.key.to_string() == mint_authority_key.to_string() + }) + .ok_or(TokenTransferError::ParseAccountFailure)?; - // Todo! - Ok(()) + let bump_vector = bump.to_le_bytes(); + let inner = vec![base_denom.as_ref(), bump_vector.as_ref()]; + let outer = vec![inner.as_slice()]; + + // Below is the actual instruction that we are going to send to the Token program. + let transfer_instruction = MintTo { + mint: token_mint.clone(), + to: receiver.clone(), + authority: mint_authority.clone(), + }; + let cpi_ctx = CpiContext::new_with_signer( + token_program.clone(), + transfer_instruction, + outer.as_slice(), //signer PDA + ); + + Ok(anchor_spl::token::mint_to(cpi_ctx, amount[0]).unwrap()) } fn burn_coins_execute( @@ -51,13 +160,68 @@ impl TokenTransferExecutionContext for IbcStorage<'_, '_, '_> { amt.denom.trace_path, amt.denom.base_denom ); + let burner_id = account.to_string(); + let base_denom = amt.denom.base_denom.to_string(); + let amount = amt.amount; + // Since amount is u256 which is array of u64, so if the amount is above u64 max, it means that the amount value at index 0 is max. + if amount[0] == u64::MAX { + return Err(TokenTransferError::InvalidAmount( + FromDecStrErr::InvalidLength, + )); + } + let (token_mint_key, bump) = + Pubkey::find_program_address(&[base_denom.as_ref()], &id()); + let (mint_authority_key, _bump) = + Pubkey::find_program_address(&[MINT_ESCROW_SEED], &id()); + let store = self.0.borrow(); + let burner = store + .accounts + .iter() + .find(|account| account.key.to_string() == burner_id) + .ok_or(TokenTransferError::ParseAccountFailure)?; + let token_mint = store + .accounts + .iter() + .find(|account| { + account.key.to_string() == token_mint_key.to_string() + }) + .ok_or(TokenTransferError::ParseAccountFailure)?; + let token_program = store + .accounts + .iter() + .find(|&account| { + account.key.to_string() == spl_token::ID.to_string() + }) + .ok_or(TokenTransferError::ParseAccountFailure)?; + let mint_authority = store + .accounts + .iter() + .find(|&account| { + account.key.to_string() == mint_authority_key.to_string() + }) + .ok_or(TokenTransferError::ParseAccountFailure)?; - // Todo! - Ok(()) + let bump_vector = bump.to_le_bytes(); + let inner = vec![base_denom.as_ref(), bump_vector.as_ref()]; + let outer = vec![inner.as_slice()]; + + // Below is the actual instruction that we are going to send to the Token program. + let transfer_instruction = Burn { + mint: token_mint.clone(), + from: burner.clone(), + authority: mint_authority.clone(), + }; + let cpi_ctx = CpiContext::new_with_signer( + token_program.clone(), + transfer_instruction, + outer.as_slice(), //signer PDA + ); + + Ok(anchor_spl::token::burn(cpi_ctx, amount[0]).unwrap()) } } -impl TokenTransferValidationContext for IbcStorage<'_, '_, '_> { +impl TokenTransferValidationContext for IbcStorage<'_, '_, '_, '_> { type AccountId = Signer; fn get_port(&self) -> Result { @@ -69,7 +233,8 @@ impl TokenTransferValidationContext for IbcStorage<'_, '_, '_> { port_id: &PortId, channel_id: &ChannelId, ) -> Result { - let seeds = [port_id.as_bytes().as_ref(), channel_id.as_bytes().as_ref()]; + let seeds = + [port_id.as_bytes().as_ref(), channel_id.as_bytes().as_ref()]; let escrow_account = Pubkey::find_program_address(&seeds, &id()); Ok(Signer::from(escrow_account.0.to_string())) } diff --git a/solana/solana-ibc/programs/solana-ibc/src/transfer/mod.rs b/solana/solana-ibc/programs/solana-ibc/src/transfer/mod.rs index 656d3d10..7b2bbc45 100644 --- a/solana/solana-ibc/programs/solana-ibc/src/transfer/mod.rs +++ b/solana/solana-ibc/programs/solana-ibc/src/transfer/mod.rs @@ -17,7 +17,7 @@ use crate::IbcStorage; mod impls; -impl Module for IbcStorage<'_, '_, '_> { +impl Module for IbcStorage<'_, '_, '_, '_> { fn on_chan_open_init_validate( &self, order: Order, diff --git a/solana/solana-ibc/programs/solana-ibc/src/validation_context.rs b/solana/solana-ibc/programs/solana-ibc/src/validation_context.rs index 93adc673..9a5f427c 100644 --- a/solana/solana-ibc/programs/solana-ibc/src/validation_context.rs +++ b/solana/solana-ibc/programs/solana-ibc/src/validation_context.rs @@ -25,7 +25,7 @@ use crate::client_state::AnyClientState; use crate::consensus_state::AnyConsensusState; use crate::IbcStorage; -impl ValidationContext for IbcStorage<'_, '_, '_> { +impl ValidationContext for IbcStorage<'_, '_, '_, '_> { type V = Self; // ClientValidationContext type E = Self; // ClientExecutionContext type AnyConsensusState = AnyConsensusState; @@ -346,7 +346,9 @@ impl ValidationContext for IbcStorage<'_, '_, '_> { } } -impl ibc::core::ics02_client::ClientValidationContext for IbcStorage<'_, '_, '_> { +impl ibc::core::ics02_client::ClientValidationContext + for IbcStorage<'_, '_, '_, '_> +{ fn client_update_time( &self, client_id: &ClientId, @@ -402,7 +404,7 @@ impl ibc::core::ics02_client::ClientValidationContext for IbcStorage<'_, '_, '_> } } -impl IbcStorage<'_, '_, '_> { +impl IbcStorage<'_, '_, '_, '_> { fn get_next_sequence( &self, path: crate::trie_key::SequencePath<'_>, From d6545d66195ab30255504b0775d1d7fd512ad0bb Mon Sep 17 00:00:00 2001 From: dhruvja Date: Thu, 2 Nov 2023 12:25:02 +0100 Subject: [PATCH 03/57] remove signer from storage --- .../programs/solana-ibc/src/client_state.rs | 10 +++++----- .../programs/solana-ibc/src/execution_context.rs | 13 ++++++------- solana/solana-ibc/programs/solana-ibc/src/lib.rs | 8 +++----- .../programs/solana-ibc/src/transfer/impls.rs | 4 ++-- .../programs/solana-ibc/src/transfer/mod.rs | 2 +- .../programs/solana-ibc/src/validation_context.rs | 6 +++--- 6 files changed, 20 insertions(+), 23 deletions(-) diff --git a/solana/solana-ibc/programs/solana-ibc/src/client_state.rs b/solana/solana-ibc/programs/solana-ibc/src/client_state.rs index 8eb98d9a..e2322c60 100644 --- a/solana/solana-ibc/programs/solana-ibc/src/client_state.rs +++ b/solana/solana-ibc/programs/solana-ibc/src/client_state.rs @@ -84,7 +84,7 @@ impl From for Any { } } -impl ClientStateValidation> for AnyClientState { +impl ClientStateValidation> for AnyClientState { fn verify_client_message( &self, ctx: &IbcStorage, @@ -289,7 +289,7 @@ impl From for AnyClientState { fn from(value: MockClientState) -> Self { AnyClientState::Mock(value) } } -impl ClientStateExecution> for AnyClientState { +impl ClientStateExecution> for AnyClientState { fn initialise( &self, ctx: &mut IbcStorage, @@ -378,7 +378,7 @@ impl ClientStateExecution> for AnyClientState { } impl ibc::clients::ics07_tendermint::CommonContext - for IbcStorage<'_, '_, '_, '_> + for IbcStorage<'_, '_, '_,> { type ConversionError = ClientError; @@ -418,7 +418,7 @@ impl ibc::clients::ics07_tendermint::CommonContext } #[cfg(any(test, feature = "mocks"))] -impl MockClientContext for IbcStorage<'_, '_, '_, '_> { +impl MockClientContext for IbcStorage<'_, '_, '_,> { type ConversionError = ClientError; type AnyConsensusState = AnyConsensusState; @@ -439,7 +439,7 @@ impl MockClientContext for IbcStorage<'_, '_, '_, '_> { } impl ibc::clients::ics07_tendermint::ValidationContext - for IbcStorage<'_, '_, '_, '_> + for IbcStorage<'_, '_, '_,> { fn next_consensus_state( &self, diff --git a/solana/solana-ibc/programs/solana-ibc/src/execution_context.rs b/solana/solana-ibc/programs/solana-ibc/src/execution_context.rs index c4de5c4f..cd8ed62c 100644 --- a/solana/solana-ibc/programs/solana-ibc/src/execution_context.rs +++ b/solana/solana-ibc/programs/solana-ibc/src/execution_context.rs @@ -33,7 +33,7 @@ use crate::{ type Result = core::result::Result; -impl ClientExecutionContext for IbcStorage<'_, '_, '_, '_> { +impl ClientExecutionContext for IbcStorage<'_, '_, '_,> { type V = Self; // ClientValidationContext type AnyClientState = AnyClientState; type AnyConsensusState = AnyConsensusState; @@ -197,7 +197,7 @@ impl ClientExecutionContext for IbcStorage<'_, '_, '_, '_> { } } -impl ExecutionContext for IbcStorage<'_, '_, '_, '_> { +impl ExecutionContext for IbcStorage<'_, '_, '_,> { fn increase_client_counter(&mut self) -> Result { let mut store = self.0.borrow_mut(); store.private.client_counter = @@ -422,8 +422,7 @@ impl ExecutionContext for IbcStorage<'_, '_, '_, '_> { seq: Sequence, ) -> Result { msg!("store_next_sequence_send: path: {path}, seq: {seq}"); - let store: &mut IbcStorageInner<'_, '_, '_, '_> = - &mut self.0.borrow_mut(); + let mut store = self.0.borrow_mut(); store.store_next_sequence( path.into(), super::SequenceTripleIdx::Send, @@ -437,7 +436,7 @@ impl ExecutionContext for IbcStorage<'_, '_, '_, '_> { seq: Sequence, ) -> Result { msg!("store_next_sequence_recv: path: {path}, seq: {seq}"); - let store: &mut IbcStorageInner<'_, '_, '_, '_> = + let store: &mut IbcStorageInner<'_, '_, '_,> = &mut self.0.borrow_mut(); store.store_next_sequence( path.into(), @@ -452,7 +451,7 @@ impl ExecutionContext for IbcStorage<'_, '_, '_, '_> { seq: Sequence, ) -> Result { msg!("store_next_sequence_ack: path: {path}, seq: {seq}"); - let store: &mut IbcStorageInner<'_, '_, '_, '_> = + let store: &mut IbcStorageInner<'_, '_, '_,> = &mut self.0.borrow_mut(); store.store_next_sequence( path.into(), @@ -498,7 +497,7 @@ impl ExecutionContext for IbcStorage<'_, '_, '_, '_> { fn get_client_execution_context(&mut self) -> &mut Self::E { self } } -impl IbcStorageInner<'_, '_, '_, '_> { +impl IbcStorageInner<'_, '_, '_,> { fn store_next_sequence( &mut self, path: crate::trie_key::SequencePath<'_>, diff --git a/solana/solana-ibc/programs/solana-ibc/src/lib.rs b/solana/solana-ibc/programs/solana-ibc/src/lib.rs index c5110473..c065f487 100644 --- a/solana/solana-ibc/programs/solana-ibc/src/lib.rs +++ b/solana/solana-ibc/programs/solana-ibc/src/lib.rs @@ -56,7 +56,6 @@ pub mod solana_ibc { private, provable, accounts: ctx.remaining_accounts.to_vec(), - signer: ctx.accounts.sender.to_account_info(), }; let mut store = IbcStorage(Rc::new(RefCell::new(inner))); let mut router = store.clone(); @@ -234,18 +233,17 @@ pub struct PrivateStorage { /// All the structs from IBC are stored as String since they dont implement AnchorSerialize and AnchorDeserialize #[derive(Debug)] -pub struct IbcStorageInner<'a, 'b, 'c, 'd> { +pub struct IbcStorageInner<'a, 'b, 'c> { pub private: &'a mut PrivateStorage, pub provable: solana_trie::AccountTrie>, pub accounts: Vec>, - pub signer: AccountInfo<'d>, } #[derive(Debug, Clone)] -struct IbcStorage<'a, 'b, 'c, 'd>(Rc>>); +struct IbcStorage<'a, 'b, 'c>(Rc>>); -impl Router for IbcStorage<'_, '_, '_, '_> { +impl Router for IbcStorage<'_, '_, '_,> { // fn get_route(&self, module_id: &ModuleId) -> Option<&dyn Module> { let module_id = core::borrow::Borrow::borrow(module_id); diff --git a/solana/solana-ibc/programs/solana-ibc/src/transfer/impls.rs b/solana/solana-ibc/programs/solana-ibc/src/transfer/impls.rs index 5acec605..ca0f2033 100644 --- a/solana/solana-ibc/programs/solana-ibc/src/transfer/impls.rs +++ b/solana/solana-ibc/programs/solana-ibc/src/transfer/impls.rs @@ -13,7 +13,7 @@ use uint::FromDecStrErr; // use crate::module_holder::IbcStorage<'_,'_>; use crate::{id, IbcStorage, MINT_ESCROW_SEED}; -impl TokenTransferExecutionContext for IbcStorage<'_, '_, '_, '_> { +impl TokenTransferExecutionContext for IbcStorage<'_, '_, '_,> { fn send_coins_execute( &mut self, from: &Self::AccountId, @@ -221,7 +221,7 @@ impl TokenTransferExecutionContext for IbcStorage<'_, '_, '_, '_> { } } -impl TokenTransferValidationContext for IbcStorage<'_, '_, '_, '_> { +impl TokenTransferValidationContext for IbcStorage<'_, '_, '_,> { type AccountId = Signer; fn get_port(&self) -> Result { diff --git a/solana/solana-ibc/programs/solana-ibc/src/transfer/mod.rs b/solana/solana-ibc/programs/solana-ibc/src/transfer/mod.rs index 7b2bbc45..2f08a481 100644 --- a/solana/solana-ibc/programs/solana-ibc/src/transfer/mod.rs +++ b/solana/solana-ibc/programs/solana-ibc/src/transfer/mod.rs @@ -17,7 +17,7 @@ use crate::IbcStorage; mod impls; -impl Module for IbcStorage<'_, '_, '_, '_> { +impl Module for IbcStorage<'_, '_, '_,> { fn on_chan_open_init_validate( &self, order: Order, diff --git a/solana/solana-ibc/programs/solana-ibc/src/validation_context.rs b/solana/solana-ibc/programs/solana-ibc/src/validation_context.rs index 9a5f427c..a418256d 100644 --- a/solana/solana-ibc/programs/solana-ibc/src/validation_context.rs +++ b/solana/solana-ibc/programs/solana-ibc/src/validation_context.rs @@ -25,7 +25,7 @@ use crate::client_state::AnyClientState; use crate::consensus_state::AnyConsensusState; use crate::IbcStorage; -impl ValidationContext for IbcStorage<'_, '_, '_, '_> { +impl ValidationContext for IbcStorage<'_, '_, '_,> { type V = Self; // ClientValidationContext type E = Self; // ClientExecutionContext type AnyConsensusState = AnyConsensusState; @@ -347,7 +347,7 @@ impl ValidationContext for IbcStorage<'_, '_, '_, '_> { } impl ibc::core::ics02_client::ClientValidationContext - for IbcStorage<'_, '_, '_, '_> + for IbcStorage<'_, '_, '_,> { fn client_update_time( &self, @@ -404,7 +404,7 @@ impl ibc::core::ics02_client::ClientValidationContext } } -impl IbcStorage<'_, '_, '_, '_> { +impl IbcStorage<'_, '_, '_,> { fn get_next_sequence( &self, path: crate::trie_key::SequencePath<'_>, From 721aa47276c2d4e8097fd3d7cd66f6d47778fbfe Mon Sep 17 00:00:00 2001 From: dhruvja Date: Thu, 2 Nov 2023 12:26:48 +0100 Subject: [PATCH 04/57] using ID instead of id() --- .../programs/solana-ibc/src/transfer/impls.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/solana/solana-ibc/programs/solana-ibc/src/transfer/impls.rs b/solana/solana-ibc/programs/solana-ibc/src/transfer/impls.rs index ca0f2033..2eae361d 100644 --- a/solana/solana-ibc/programs/solana-ibc/src/transfer/impls.rs +++ b/solana/solana-ibc/programs/solana-ibc/src/transfer/impls.rs @@ -11,7 +11,7 @@ use ibc::Signer; use uint::FromDecStrErr; // use crate::module_holder::IbcStorage<'_,'_>; -use crate::{id, IbcStorage, MINT_ESCROW_SEED}; +use crate::{IbcStorage, MINT_ESCROW_SEED}; impl TokenTransferExecutionContext for IbcStorage<'_, '_, '_,> { fn send_coins_execute( @@ -39,7 +39,7 @@ impl TokenTransferExecutionContext for IbcStorage<'_, '_, '_,> { )); } let (_token_mint_key, bump) = - Pubkey::find_program_address(&[base_denom.as_ref()], &id()); + Pubkey::find_program_address(&[base_denom.as_ref()], &crate::ID); let store = self.0.borrow(); let sender = store .accounts @@ -99,9 +99,9 @@ impl TokenTransferExecutionContext for IbcStorage<'_, '_, '_,> { )); } let (token_mint_key, bump) = - Pubkey::find_program_address(&[base_denom.as_ref()], &id()); + Pubkey::find_program_address(&[base_denom.as_ref()], &crate::ID); let (mint_authority_key, _bump) = - Pubkey::find_program_address(&[MINT_ESCROW_SEED], &id()); + Pubkey::find_program_address(&[MINT_ESCROW_SEED], &crate::ID); let store = self.0.borrow(); let receiver = store .accounts @@ -170,9 +170,9 @@ impl TokenTransferExecutionContext for IbcStorage<'_, '_, '_,> { )); } let (token_mint_key, bump) = - Pubkey::find_program_address(&[base_denom.as_ref()], &id()); + Pubkey::find_program_address(&[base_denom.as_ref()], &crate::ID); let (mint_authority_key, _bump) = - Pubkey::find_program_address(&[MINT_ESCROW_SEED], &id()); + Pubkey::find_program_address(&[MINT_ESCROW_SEED], &crate::ID); let store = self.0.borrow(); let burner = store .accounts @@ -235,7 +235,7 @@ impl TokenTransferValidationContext for IbcStorage<'_, '_, '_,> { ) -> Result { let seeds = [port_id.as_bytes().as_ref(), channel_id.as_bytes().as_ref()]; - let escrow_account = Pubkey::find_program_address(&seeds, &id()); + let escrow_account = Pubkey::find_program_address(&seeds, &crate::ID); Ok(Signer::from(escrow_account.0.to_string())) } From 8bc1c8e627bc0cf623dedee92d4e65d986528dc9 Mon Sep 17 00:00:00 2001 From: dhruvja Date: Thu, 2 Nov 2023 12:35:43 +0100 Subject: [PATCH 05/57] compare pubkeys directlu --- .../programs/solana-ibc/src/transfer/impls.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/solana/solana-ibc/programs/solana-ibc/src/transfer/impls.rs b/solana/solana-ibc/programs/solana-ibc/src/transfer/impls.rs index 2eae361d..e8bcdb41 100644 --- a/solana/solana-ibc/programs/solana-ibc/src/transfer/impls.rs +++ b/solana/solana-ibc/programs/solana-ibc/src/transfer/impls.rs @@ -55,7 +55,7 @@ impl TokenTransferExecutionContext for IbcStorage<'_, '_, '_,> { .accounts .iter() .find(|&account| { - account.key.to_string() == spl_token::ID.to_string() + account.key == &spl_token::ID }) .ok_or(TokenTransferError::ParseAccountFailure)?; @@ -112,21 +112,21 @@ impl TokenTransferExecutionContext for IbcStorage<'_, '_, '_,> { .accounts .iter() .find(|account| { - account.key.to_string() == token_mint_key.to_string() + account.key == &token_mint_key }) .ok_or(TokenTransferError::ParseAccountFailure)?; let token_program = store .accounts .iter() .find(|&account| { - account.key.to_string() == spl_token::ID.to_string() + account.key == &spl_token::ID }) .ok_or(TokenTransferError::ParseAccountFailure)?; let mint_authority = store .accounts .iter() .find(|&account| { - account.key.to_string() == mint_authority_key.to_string() + account.key == &mint_authority_key }) .ok_or(TokenTransferError::ParseAccountFailure)?; @@ -183,21 +183,21 @@ impl TokenTransferExecutionContext for IbcStorage<'_, '_, '_,> { .accounts .iter() .find(|account| { - account.key.to_string() == token_mint_key.to_string() + account.key == &token_mint_key }) .ok_or(TokenTransferError::ParseAccountFailure)?; let token_program = store .accounts .iter() .find(|&account| { - account.key.to_string() == spl_token::ID.to_string() + account.key == &spl_token::ID }) .ok_or(TokenTransferError::ParseAccountFailure)?; let mint_authority = store .accounts .iter() .find(|&account| { - account.key.to_string() == mint_authority_key.to_string() + account.key == &mint_authority_key }) .ok_or(TokenTransferError::ParseAccountFailure)?; From 9e33c184459dd8400895ca44a20a25312b329274 Mon Sep 17 00:00:00 2001 From: dhruvja Date: Thu, 2 Nov 2023 12:45:05 +0100 Subject: [PATCH 06/57] rm unneccesary conversions to string --- .../programs/solana-ibc/src/transfer/impls.rs | 20 +++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/solana/solana-ibc/programs/solana-ibc/src/transfer/impls.rs b/solana/solana-ibc/programs/solana-ibc/src/transfer/impls.rs index e8bcdb41..5c161861 100644 --- a/solana/solana-ibc/programs/solana-ibc/src/transfer/impls.rs +++ b/solana/solana-ibc/programs/solana-ibc/src/transfer/impls.rs @@ -1,3 +1,5 @@ +use std::str::FromStr; + use anchor_lang::prelude::{CpiContext, Pubkey}; use anchor_lang::solana_program::msg; use anchor_spl::token::{spl_token, Burn, MintTo, Transfer}; @@ -28,8 +30,8 @@ impl TokenTransferExecutionContext for IbcStorage<'_, '_, '_,> { amt.denom.trace_path, amt.denom.base_denom ); - let sender_id = from.to_string(); - let receiver_id = to.to_string(); + let sender_id = Pubkey::from_str(&from.to_string()).unwrap(); + let receiver_id = Pubkey::from_str(&to.to_string()).unwrap(); let base_denom = amt.denom.base_denom.to_string(); let amount = amt.amount; // Since amount is u256 which is array of u64, so if the amount is above u64 max, it means that the amount value at index 0 is max. @@ -44,12 +46,12 @@ impl TokenTransferExecutionContext for IbcStorage<'_, '_, '_,> { let sender = store .accounts .iter() - .find(|account| account.key.to_string() == sender_id) + .find(|account| account.key == &sender_id) .ok_or(TokenTransferError::ParseAccountFailure)?; let receiver = store .accounts .iter() - .find(|account| account.key.to_string() == receiver_id) + .find(|account| account.key == &receiver_id) .ok_or(TokenTransferError::ParseAccountFailure)?; let token_program = store .accounts @@ -89,7 +91,7 @@ impl TokenTransferExecutionContext for IbcStorage<'_, '_, '_,> { amt.denom.trace_path, amt.denom.base_denom ); - let receiver_id = account.to_string(); + let receiver_id = Pubkey::from_str(&account.to_string()).unwrap(); let base_denom = amt.denom.base_denom.to_string(); let amount = amt.amount; // Since amount is u256 which is array of u64, so if the amount is above u64 max, it means that the amount value at index 0 is max. @@ -106,7 +108,7 @@ impl TokenTransferExecutionContext for IbcStorage<'_, '_, '_,> { let receiver = store .accounts .iter() - .find(|account| account.key.to_string() == receiver_id) + .find(|account| account.key == &receiver_id) .ok_or(TokenTransferError::ParseAccountFailure)?; let token_mint = store .accounts @@ -160,7 +162,7 @@ impl TokenTransferExecutionContext for IbcStorage<'_, '_, '_,> { amt.denom.trace_path, amt.denom.base_denom ); - let burner_id = account.to_string(); + let burner_id = Pubkey::from_str(&account.to_string()).unwrap(); let base_denom = amt.denom.base_denom.to_string(); let amount = amt.amount; // Since amount is u256 which is array of u64, so if the amount is above u64 max, it means that the amount value at index 0 is max. @@ -177,7 +179,7 @@ impl TokenTransferExecutionContext for IbcStorage<'_, '_, '_,> { let burner = store .accounts .iter() - .find(|account| account.key.to_string() == burner_id) + .find(|account| account.key == &burner_id) .ok_or(TokenTransferError::ParseAccountFailure)?; let token_mint = store .accounts @@ -274,3 +276,5 @@ impl TokenTransferValidationContext for IbcStorage<'_, '_, '_,> { Ok(()) } } + +// fn get_account_info_from_key(accounts: Vec>, key: Pubkey) -> \ No newline at end of file From fea16ecac117e4dfeb5ef8b4d2d46d4833e4f740 Mon Sep 17 00:00:00 2001 From: dhruvja Date: Thu, 2 Nov 2023 13:15:12 +0100 Subject: [PATCH 07/57] extract getting account info in a seperate method --- .../programs/solana-ibc/src/transfer/impls.rs | 93 +++++-------------- 1 file changed, 21 insertions(+), 72 deletions(-) diff --git a/solana/solana-ibc/programs/solana-ibc/src/transfer/impls.rs b/solana/solana-ibc/programs/solana-ibc/src/transfer/impls.rs index 5c161861..459e1612 100644 --- a/solana/solana-ibc/programs/solana-ibc/src/transfer/impls.rs +++ b/solana/solana-ibc/programs/solana-ibc/src/transfer/impls.rs @@ -1,6 +1,6 @@ use std::str::FromStr; -use anchor_lang::prelude::{CpiContext, Pubkey}; +use anchor_lang::prelude::{CpiContext, Pubkey, AccountInfo}; use anchor_lang::solana_program::msg; use anchor_spl::token::{spl_token, Burn, MintTo, Transfer}; use ibc::applications::transfer::context::{ @@ -43,24 +43,10 @@ impl TokenTransferExecutionContext for IbcStorage<'_, '_, '_,> { let (_token_mint_key, bump) = Pubkey::find_program_address(&[base_denom.as_ref()], &crate::ID); let store = self.0.borrow(); - let sender = store - .accounts - .iter() - .find(|account| account.key == &sender_id) - .ok_or(TokenTransferError::ParseAccountFailure)?; - let receiver = store - .accounts - .iter() - .find(|account| account.key == &receiver_id) - .ok_or(TokenTransferError::ParseAccountFailure)?; - let token_program = store - .accounts - .iter() - .find(|&account| { - account.key == &spl_token::ID - }) - .ok_or(TokenTransferError::ParseAccountFailure)?; - + let accounts = &store.accounts; + let sender = get_account_info_from_key(accounts, sender_id)?; + let receiver = get_account_info_from_key(accounts, receiver_id)?; + let token_program = get_account_info_from_key(accounts, spl_token::ID)?; let bump_vector = bump.to_le_bytes(); let inner = vec![base_denom.as_ref(), bump_vector.as_ref()]; let outer = vec![inner.as_slice()]; @@ -105,32 +91,11 @@ impl TokenTransferExecutionContext for IbcStorage<'_, '_, '_,> { let (mint_authority_key, _bump) = Pubkey::find_program_address(&[MINT_ESCROW_SEED], &crate::ID); let store = self.0.borrow(); - let receiver = store - .accounts - .iter() - .find(|account| account.key == &receiver_id) - .ok_or(TokenTransferError::ParseAccountFailure)?; - let token_mint = store - .accounts - .iter() - .find(|account| { - account.key == &token_mint_key - }) - .ok_or(TokenTransferError::ParseAccountFailure)?; - let token_program = store - .accounts - .iter() - .find(|&account| { - account.key == &spl_token::ID - }) - .ok_or(TokenTransferError::ParseAccountFailure)?; - let mint_authority = store - .accounts - .iter() - .find(|&account| { - account.key == &mint_authority_key - }) - .ok_or(TokenTransferError::ParseAccountFailure)?; + let accounts = &store.accounts; + let receiver = get_account_info_from_key(accounts, receiver_id)?; + let token_mint = get_account_info_from_key(accounts, token_mint_key)?; + let token_program = get_account_info_from_key(accounts, spl_token::ID)?; + let mint_authority = get_account_info_from_key(accounts, mint_authority_key)?; let bump_vector = bump.to_le_bytes(); let inner = vec![base_denom.as_ref(), bump_vector.as_ref()]; @@ -176,32 +141,11 @@ impl TokenTransferExecutionContext for IbcStorage<'_, '_, '_,> { let (mint_authority_key, _bump) = Pubkey::find_program_address(&[MINT_ESCROW_SEED], &crate::ID); let store = self.0.borrow(); - let burner = store - .accounts - .iter() - .find(|account| account.key == &burner_id) - .ok_or(TokenTransferError::ParseAccountFailure)?; - let token_mint = store - .accounts - .iter() - .find(|account| { - account.key == &token_mint_key - }) - .ok_or(TokenTransferError::ParseAccountFailure)?; - let token_program = store - .accounts - .iter() - .find(|&account| { - account.key == &spl_token::ID - }) - .ok_or(TokenTransferError::ParseAccountFailure)?; - let mint_authority = store - .accounts - .iter() - .find(|&account| { - account.key == &mint_authority_key - }) - .ok_or(TokenTransferError::ParseAccountFailure)?; + let accounts = &store.accounts; + let burner = get_account_info_from_key(accounts, burner_id)?; + let token_mint = get_account_info_from_key(accounts, token_mint_key)?; + let token_program = get_account_info_from_key(accounts, spl_token::ID)?; + let mint_authority = get_account_info_from_key(accounts, mint_authority_key)?; let bump_vector = bump.to_le_bytes(); let inner = vec![base_denom.as_ref(), bump_vector.as_ref()]; @@ -277,4 +221,9 @@ impl TokenTransferValidationContext for IbcStorage<'_, '_, '_,> { } } -// fn get_account_info_from_key(accounts: Vec>, key: Pubkey) -> \ No newline at end of file +fn get_account_info_from_key<'a, 'b>(accounts: &'a Vec>, key: Pubkey) -> Result<&'a AccountInfo<'b>, TokenTransferError> { + accounts + .iter() + .find(|account| account.key == &key) + .ok_or(TokenTransferError::ParseAccountFailure) +} \ No newline at end of file From 03fe114f0030f7a0176a2d47f83ff04b505111ba Mon Sep 17 00:00:00 2001 From: dhruvja Date: Thu, 2 Nov 2023 14:46:55 +0100 Subject: [PATCH 08/57] converting u256 to u64 --- Cargo.toml | 1 + solana/solana-ibc/programs/solana-ibc/Cargo.toml | 1 + .../programs/solana-ibc/src/transfer/impls.rs | 10 +++++++--- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index d7741c8e..aac9406c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -41,6 +41,7 @@ solana-client = "1.16.14" solana-program = "1.16.14" solana-sdk = "1.16.14" strum = { version = "0.25.0", default-features = false, features = ["derive"] } +primitive-types = "0.12.2" lib = { path = "common/lib" } memory = { path = "common/memory" } diff --git a/solana/solana-ibc/programs/solana-ibc/Cargo.toml b/solana/solana-ibc/programs/solana-ibc/Cargo.toml index c9dfc296..72c58b8d 100644 --- a/solana/solana-ibc/programs/solana-ibc/Cargo.toml +++ b/solana/solana-ibc/programs/solana-ibc/Cargo.toml @@ -23,6 +23,7 @@ ibc.workspace = true ibc-proto.workspace = true serde.workspace = true serde_json.workspace = true +primitive-types.workspace = true lib.workspace = true memory.workspace = true diff --git a/solana/solana-ibc/programs/solana-ibc/src/transfer/impls.rs b/solana/solana-ibc/programs/solana-ibc/src/transfer/impls.rs index 459e1612..3ca433ba 100644 --- a/solana/solana-ibc/programs/solana-ibc/src/transfer/impls.rs +++ b/solana/solana-ibc/programs/solana-ibc/src/transfer/impls.rs @@ -1,3 +1,4 @@ +use std::ops::Deref; use std::str::FromStr; use anchor_lang::prelude::{CpiContext, Pubkey, AccountInfo}; @@ -11,6 +12,7 @@ use ibc::applications::transfer::PrefixedCoin; use ibc::core::ics24_host::identifier::{ChannelId, PortId}; use ibc::Signer; use uint::FromDecStrErr; +use primitive_types::U256; // use crate::module_holder::IbcStorage<'_,'_>; use crate::{IbcStorage, MINT_ESCROW_SEED}; @@ -34,6 +36,8 @@ impl TokenTransferExecutionContext for IbcStorage<'_, '_, '_,> { let receiver_id = Pubkey::from_str(&to.to_string()).unwrap(); let base_denom = amt.denom.base_denom.to_string(); let amount = amt.amount; + let amount_slice = amount.deref(); + let amount_u64 = amount_slice[0]; // Since amount is u256 which is array of u64, so if the amount is above u64 max, it means that the amount value at index 0 is max. if amount[0] == u64::MAX { return Err(TokenTransferError::InvalidAmount( @@ -63,7 +67,7 @@ impl TokenTransferExecutionContext for IbcStorage<'_, '_, '_,> { outer.as_slice(), //signer PDA ); - Ok(anchor_spl::token::transfer(cpi_ctx, amount[0]).unwrap()) + Ok(anchor_spl::token::transfer(cpi_ctx, U256::from(amount).as_u64()).unwrap()) } fn mint_coins_execute( @@ -113,7 +117,7 @@ impl TokenTransferExecutionContext for IbcStorage<'_, '_, '_,> { outer.as_slice(), //signer PDA ); - Ok(anchor_spl::token::mint_to(cpi_ctx, amount[0]).unwrap()) + Ok(anchor_spl::token::mint_to(cpi_ctx, U256::from(amount).as_u64()).unwrap()) } fn burn_coins_execute( @@ -163,7 +167,7 @@ impl TokenTransferExecutionContext for IbcStorage<'_, '_, '_,> { outer.as_slice(), //signer PDA ); - Ok(anchor_spl::token::burn(cpi_ctx, amount[0]).unwrap()) + Ok(anchor_spl::token::burn(cpi_ctx, U256::from(amount).as_u64()).unwrap()) } } From 7b4b01d2dbfba2fa927f96db606d87c9b7d4a27e Mon Sep 17 00:00:00 2001 From: dhruvja Date: Thu, 2 Nov 2023 15:06:11 +0100 Subject: [PATCH 09/57] added wrapped type for Pubkey to implement tryFrom --- .../programs/solana-ibc/src/transfer/impls.rs | 76 ++++++++++--------- 1 file changed, 42 insertions(+), 34 deletions(-) diff --git a/solana/solana-ibc/programs/solana-ibc/src/transfer/impls.rs b/solana/solana-ibc/programs/solana-ibc/src/transfer/impls.rs index 3ca433ba..3e3ecdfd 100644 --- a/solana/solana-ibc/programs/solana-ibc/src/transfer/impls.rs +++ b/solana/solana-ibc/programs/solana-ibc/src/transfer/impls.rs @@ -1,22 +1,32 @@ -use std::ops::Deref; use std::str::FromStr; use anchor_lang::prelude::{CpiContext, Pubkey, AccountInfo}; use anchor_lang::solana_program::msg; +use anchor_lang::solana_program::pubkey::ParsePubkeyError; use anchor_spl::token::{spl_token, Burn, MintTo, Transfer}; use ibc::applications::transfer::context::{ TokenTransferExecutionContext, TokenTransferValidationContext, }; use ibc::applications::transfer::error::TokenTransferError; -use ibc::applications::transfer::PrefixedCoin; +use ibc::applications::transfer::{PrefixedCoin, Amount}; use ibc::core::ics24_host::identifier::{ChannelId, PortId}; -use ibc::Signer; use uint::FromDecStrErr; use primitive_types::U256; // use crate::module_holder::IbcStorage<'_,'_>; use crate::{IbcStorage, MINT_ESCROW_SEED}; +pub struct InnerPubkey(pub Pubkey); + +impl TryFrom for InnerPubkey { + + type Error = ParsePubkeyError; + + fn try_from(value: ibc::Signer) -> Result { + Ok(InnerPubkey(Pubkey::from_str(&value.to_string())?)) + } +} + impl TokenTransferExecutionContext for IbcStorage<'_, '_, '_,> { fn send_coins_execute( &mut self, @@ -27,23 +37,18 @@ impl TokenTransferExecutionContext for IbcStorage<'_, '_, '_,> { msg!( "Sending coins from account {} to account {}, trace path {}, base \ denom {}", - from, - to, + from.0, + to.0, amt.denom.trace_path, amt.denom.base_denom ); - let sender_id = Pubkey::from_str(&from.to_string()).unwrap(); - let receiver_id = Pubkey::from_str(&to.to_string()).unwrap(); + let sender_id = from.0; + let receiver_id = to.0; let base_denom = amt.denom.base_denom.to_string(); let amount = amt.amount; - let amount_slice = amount.deref(); - let amount_u64 = amount_slice[0]; - // Since amount is u256 which is array of u64, so if the amount is above u64 max, it means that the amount value at index 0 is max. - if amount[0] == u64::MAX { - return Err(TokenTransferError::InvalidAmount( - FromDecStrErr::InvalidLength, - )); - } + + check_amount_overflow(amount)?; + let (_token_mint_key, bump) = Pubkey::find_program_address(&[base_denom.as_ref()], &crate::ID); let store = self.0.borrow(); @@ -77,19 +82,16 @@ impl TokenTransferExecutionContext for IbcStorage<'_, '_, '_,> { ) -> Result<(), TokenTransferError> { msg!( "Minting coins for account {}, trace path {}, base denom {}", - account, + account.0, amt.denom.trace_path, amt.denom.base_denom ); - let receiver_id = Pubkey::from_str(&account.to_string()).unwrap(); + let receiver_id = account.0; let base_denom = amt.denom.base_denom.to_string(); let amount = amt.amount; - // Since amount is u256 which is array of u64, so if the amount is above u64 max, it means that the amount value at index 0 is max. - if amount[0] == u64::MAX { - return Err(TokenTransferError::InvalidAmount( - FromDecStrErr::InvalidLength, - )); - } + + check_amount_overflow(amount)?; + let (token_mint_key, bump) = Pubkey::find_program_address(&[base_denom.as_ref()], &crate::ID); let (mint_authority_key, _bump) = @@ -127,19 +129,14 @@ impl TokenTransferExecutionContext for IbcStorage<'_, '_, '_,> { ) -> Result<(), TokenTransferError> { msg!( "Burning coins for account {}, trace path {}, base denom {}", - account, + account.0, amt.denom.trace_path, amt.denom.base_denom ); - let burner_id = Pubkey::from_str(&account.to_string()).unwrap(); + let burner_id = account.0; let base_denom = amt.denom.base_denom.to_string(); let amount = amt.amount; - // Since amount is u256 which is array of u64, so if the amount is above u64 max, it means that the amount value at index 0 is max. - if amount[0] == u64::MAX { - return Err(TokenTransferError::InvalidAmount( - FromDecStrErr::InvalidLength, - )); - } + check_amount_overflow(amount)?; let (token_mint_key, bump) = Pubkey::find_program_address(&[base_denom.as_ref()], &crate::ID); let (mint_authority_key, _bump) = @@ -172,7 +169,7 @@ impl TokenTransferExecutionContext for IbcStorage<'_, '_, '_,> { } impl TokenTransferValidationContext for IbcStorage<'_, '_, '_,> { - type AccountId = Signer; + type AccountId = InnerPubkey; fn get_port(&self) -> Result { Ok(PortId::transfer()) @@ -185,8 +182,8 @@ impl TokenTransferValidationContext for IbcStorage<'_, '_, '_,> { ) -> Result { let seeds = [port_id.as_bytes().as_ref(), channel_id.as_bytes().as_ref()]; - let escrow_account = Pubkey::find_program_address(&seeds, &crate::ID); - Ok(Signer::from(escrow_account.0.to_string())) + let (escrow_account_key, _bump )= Pubkey::find_program_address(&seeds, &crate::ID); + Ok(InnerPubkey(escrow_account_key)) } fn can_send_coins(&self) -> Result<(), TokenTransferError> { @@ -230,4 +227,15 @@ fn get_account_info_from_key<'a, 'b>(accounts: &'a Vec>, key: Pu .iter() .find(|account| account.key == &key) .ok_or(TokenTransferError::ParseAccountFailure) +} + +fn check_amount_overflow(amount: Amount) -> Result<(), TokenTransferError> { + // Solana transfer only supports u64 so checking if the token transfer amount overflows. If it overflows we return an error + // Since amount is u256 which is array of u64, so if the amount is above u64 max, it means that the amount value at index 0 is max. + if amount[0] == u64::MAX { + return Err(TokenTransferError::InvalidAmount( + FromDecStrErr::InvalidLength, + )); + } + Ok(()) } \ No newline at end of file From 7caecf5efcd420344f93250d14d197a8541c1139 Mon Sep 17 00:00:00 2001 From: dhruvja Date: Thu, 2 Nov 2023 15:19:57 +0100 Subject: [PATCH 10/57] renamed pubkey --- .../programs/solana-ibc/src/transfer/impls.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/solana/solana-ibc/programs/solana-ibc/src/transfer/impls.rs b/solana/solana-ibc/programs/solana-ibc/src/transfer/impls.rs index 3e3ecdfd..661fd651 100644 --- a/solana/solana-ibc/programs/solana-ibc/src/transfer/impls.rs +++ b/solana/solana-ibc/programs/solana-ibc/src/transfer/impls.rs @@ -16,14 +16,14 @@ use primitive_types::U256; // use crate::module_holder::IbcStorage<'_,'_>; use crate::{IbcStorage, MINT_ESCROW_SEED}; -pub struct InnerPubkey(pub Pubkey); +pub struct AccountId(Pubkey); -impl TryFrom for InnerPubkey { +impl TryFrom for AccountId { type Error = ParsePubkeyError; fn try_from(value: ibc::Signer) -> Result { - Ok(InnerPubkey(Pubkey::from_str(&value.to_string())?)) + Ok(AccountId(Pubkey::from_str(&value.to_string())?)) } } @@ -169,7 +169,7 @@ impl TokenTransferExecutionContext for IbcStorage<'_, '_, '_,> { } impl TokenTransferValidationContext for IbcStorage<'_, '_, '_,> { - type AccountId = InnerPubkey; + type AccountId = AccountId; fn get_port(&self) -> Result { Ok(PortId::transfer()) @@ -183,7 +183,7 @@ impl TokenTransferValidationContext for IbcStorage<'_, '_, '_,> { let seeds = [port_id.as_bytes().as_ref(), channel_id.as_bytes().as_ref()]; let (escrow_account_key, _bump )= Pubkey::find_program_address(&seeds, &crate::ID); - Ok(InnerPubkey(escrow_account_key)) + Ok(AccountId(escrow_account_key)) } fn can_send_coins(&self) -> Result<(), TokenTransferError> { From 02793acea86aa2120046f36c7bf58ca4ccf2ce4b Mon Sep 17 00:00:00 2001 From: dhruvja Date: Thu, 2 Nov 2023 16:19:12 +0100 Subject: [PATCH 11/57] added suggestions --- .../programs/solana-ibc/src/transfer/impls.rs | 21 ++++++++----------- 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/solana/solana-ibc/programs/solana-ibc/src/transfer/impls.rs b/solana/solana-ibc/programs/solana-ibc/src/transfer/impls.rs index 676e8158..d80b6898 100644 --- a/solana/solana-ibc/programs/solana-ibc/src/transfer/impls.rs +++ b/solana/solana-ibc/programs/solana-ibc/src/transfer/impls.rs @@ -2,7 +2,6 @@ use std::str::FromStr; use anchor_lang::prelude::{AccountInfo, CpiContext, Pubkey}; use anchor_lang::solana_program::msg; -use anchor_lang::solana_program::pubkey::ParsePubkeyError; use anchor_spl::token::{spl_token, Burn, MintTo, Transfer}; use ibc::applications::transfer::context::{ TokenTransferExecutionContext, TokenTransferValidationContext, @@ -19,10 +18,10 @@ use crate::{storage::IbcStorage, MINT_ESCROW_SEED}; pub struct AccountId(Pubkey); impl TryFrom for AccountId { - type Error = ParsePubkeyError; + type Error = ::Err; fn try_from(value: ibc::Signer) -> Result { - Ok(AccountId(Pubkey::from_str(&value.to_string())?)) + Ok(Pubkey::from_str(&value.as_ref()).map(Self)?) } } @@ -237,13 +236,11 @@ fn get_account_info_from_key<'a, 'b>( .ok_or(TokenTransferError::ParseAccountFailure) } -fn check_amount_overflow(amount: Amount) -> Result<(), TokenTransferError> { - // Solana transfer only supports u64 so checking if the token transfer amount overflows. If it overflows we return an error - // Since amount is u256 which is array of u64, so if the amount is above u64 max, it means that the amount value at index 0 is max. - if amount[0] == u64::MAX { - return Err(TokenTransferError::InvalidAmount( - FromDecStrErr::InvalidLength, - )); - } - Ok(()) +/// Solana transfer only supports u64 so checking if the token transfer amount overflows. If it overflows we return an error else we return the converted u64 +fn check_amount_overflow(amount: Amount) -> Result { + u64::try_from(U256::from(amount)).map_err(|_| { + TokenTransferError::InvalidAmount( + FromDecStrErr::InvalidLength + ) + }) } From cf31b0232978e6a9e91e975eaf86b15f4e5ac833 Mon Sep 17 00:00:00 2001 From: dhruvja Date: Thu, 2 Nov 2023 16:22:09 +0100 Subject: [PATCH 12/57] using converted u64 amount from the method --- .../programs/solana-ibc/src/transfer/impls.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/solana/solana-ibc/programs/solana-ibc/src/transfer/impls.rs b/solana/solana-ibc/programs/solana-ibc/src/transfer/impls.rs index d80b6898..6ddd341d 100644 --- a/solana/solana-ibc/programs/solana-ibc/src/transfer/impls.rs +++ b/solana/solana-ibc/programs/solana-ibc/src/transfer/impls.rs @@ -45,7 +45,7 @@ impl TokenTransferExecutionContext for IbcStorage<'_, '_, '_> { let base_denom = amt.denom.base_denom.to_string(); let amount = amt.amount; - check_amount_overflow(amount)?; + let amount_in_u64 = check_amount_overflow(amount)?; let (_token_mint_key, bump) = Pubkey::find_program_address(&[base_denom.as_ref()], &crate::ID); @@ -70,7 +70,7 @@ impl TokenTransferExecutionContext for IbcStorage<'_, '_, '_> { outer.as_slice(), //signer PDA ); - Ok(anchor_spl::token::transfer(cpi_ctx, U256::from(amount).as_u64()) + Ok(anchor_spl::token::transfer(cpi_ctx, amount_in_u64) .unwrap()) } @@ -89,7 +89,7 @@ impl TokenTransferExecutionContext for IbcStorage<'_, '_, '_> { let base_denom = amt.denom.base_denom.to_string(); let amount = amt.amount; - check_amount_overflow(amount)?; + let amount_in_u64 = check_amount_overflow(amount)?; let (token_mint_key, bump) = Pubkey::find_program_address(&[base_denom.as_ref()], &crate::ID); @@ -119,7 +119,7 @@ impl TokenTransferExecutionContext for IbcStorage<'_, '_, '_> { outer.as_slice(), //signer PDA ); - Ok(anchor_spl::token::mint_to(cpi_ctx, U256::from(amount).as_u64()) + Ok(anchor_spl::token::mint_to(cpi_ctx, amount_in_u64) .unwrap()) } @@ -137,7 +137,7 @@ impl TokenTransferExecutionContext for IbcStorage<'_, '_, '_> { let burner_id = account.0; let base_denom = amt.denom.base_denom.to_string(); let amount = amt.amount; - check_amount_overflow(amount)?; + let amount_in_u64 = check_amount_overflow(amount)?; let (token_mint_key, bump) = Pubkey::find_program_address(&[base_denom.as_ref()], &crate::ID); let (mint_authority_key, _bump) = @@ -166,7 +166,7 @@ impl TokenTransferExecutionContext for IbcStorage<'_, '_, '_> { outer.as_slice(), //signer PDA ); - Ok(anchor_spl::token::burn(cpi_ctx, U256::from(amount).as_u64()) + Ok(anchor_spl::token::burn(cpi_ctx, amount_in_u64) .unwrap()) } } From 5d0480621cb5b52024771d2b991419c2e65ea245 Mon Sep 17 00:00:00 2001 From: dhruvja Date: Thu, 2 Nov 2023 16:25:29 +0100 Subject: [PATCH 13/57] using slice arg instead of vector in transfer impl --- solana/solana-ibc/programs/solana-ibc/src/transfer/impls.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/solana/solana-ibc/programs/solana-ibc/src/transfer/impls.rs b/solana/solana-ibc/programs/solana-ibc/src/transfer/impls.rs index 6ddd341d..e1eabc9c 100644 --- a/solana/solana-ibc/programs/solana-ibc/src/transfer/impls.rs +++ b/solana/solana-ibc/programs/solana-ibc/src/transfer/impls.rs @@ -227,7 +227,7 @@ impl TokenTransferValidationContext for IbcStorage<'_, '_, '_> { } fn get_account_info_from_key<'a, 'b>( - accounts: &'a Vec>, + accounts: &'a [AccountInfo<'b>], key: Pubkey, ) -> Result<&'a AccountInfo<'b>, TokenTransferError> { accounts From 997df55702eb0c8f544bd08ad8e2c47295e256ae Mon Sep 17 00:00:00 2001 From: dhruvja Date: Fri, 3 Nov 2023 12:34:30 +0100 Subject: [PATCH 14/57] added traits for the wrapped type --- .../solana-ibc/programs/solana-ibc/Cargo.toml | 1 + .../programs/solana-ibc/src/transfer/impls.rs | 59 +++++++++++++------ 2 files changed, 43 insertions(+), 17 deletions(-) diff --git a/solana/solana-ibc/programs/solana-ibc/Cargo.toml b/solana/solana-ibc/programs/solana-ibc/Cargo.toml index ba9635e6..051ec0ba 100644 --- a/solana/solana-ibc/programs/solana-ibc/Cargo.toml +++ b/solana/solana-ibc/programs/solana-ibc/Cargo.toml @@ -25,6 +25,7 @@ serde.workspace = true serde_json.workspace = true primitive-types.workspace = true strum.workspace = true +derive_more.workspace = true lib.workspace = true memory.workspace = true diff --git a/solana/solana-ibc/programs/solana-ibc/src/transfer/impls.rs b/solana/solana-ibc/programs/solana-ibc/src/transfer/impls.rs index e1eabc9c..ca1dc6bf 100644 --- a/solana/solana-ibc/programs/solana-ibc/src/transfer/impls.rs +++ b/solana/solana-ibc/programs/solana-ibc/src/transfer/impls.rs @@ -15,6 +15,8 @@ use uint::FromDecStrErr; // use crate::module_holder::IbcStorage<'_,'_>; use crate::{storage::IbcStorage, MINT_ESCROW_SEED}; +#[derive(Clone, PartialEq, Eq, derive_more::From, derive_more::Into)] +#[into(owned, ref, ref_mut)] pub struct AccountId(Pubkey); impl TryFrom for AccountId { @@ -25,6 +27,34 @@ impl TryFrom for AccountId { } } +impl PartialEq for AccountId { + #[inline] + fn eq(&self, rhs: &Pubkey) -> bool { &self.0 == rhs } +} + +impl PartialEq for Pubkey { + #[inline] + fn eq(&self, rhs: &AccountId) -> bool { self == &rhs.0 } +} + +impl core::fmt::Debug for AccountId { + #[inline] + fn fmt(&self, fmtr: &mut core::fmt::Formatter) -> core::fmt::Result { + self.0.fmt(fmtr) + } +} + +impl core::fmt::Display for AccountId { + #[inline] + fn fmt(&self, fmtr: &mut core::fmt::Formatter) -> core::fmt::Result { + self.0.fmt(fmtr) + } +} + +impl AccountId { + fn to_pubkey(&self) -> Pubkey { self.0 } +} + impl TokenTransferExecutionContext for IbcStorage<'_, '_, '_> { fn send_coins_execute( &mut self, @@ -35,13 +65,13 @@ impl TokenTransferExecutionContext for IbcStorage<'_, '_, '_> { msg!( "Sending coins from account {} to account {}, trace path {}, base \ denom {}", - from.0, - to.0, + from, + to, amt.denom.trace_path, amt.denom.base_denom ); - let sender_id = from.0; - let receiver_id = to.0; + let sender_id = from.to_pubkey(); + let receiver_id = to.to_pubkey(); let base_denom = amt.denom.base_denom.to_string(); let amount = amt.amount; @@ -70,8 +100,7 @@ impl TokenTransferExecutionContext for IbcStorage<'_, '_, '_> { outer.as_slice(), //signer PDA ); - Ok(anchor_spl::token::transfer(cpi_ctx, amount_in_u64) - .unwrap()) + Ok(anchor_spl::token::transfer(cpi_ctx, amount_in_u64).unwrap()) } fn mint_coins_execute( @@ -81,11 +110,11 @@ impl TokenTransferExecutionContext for IbcStorage<'_, '_, '_> { ) -> Result<(), TokenTransferError> { msg!( "Minting coins for account {}, trace path {}, base denom {}", - account.0, + account, amt.denom.trace_path, amt.denom.base_denom ); - let receiver_id = account.0; + let receiver_id = account.to_pubkey(); let base_denom = amt.denom.base_denom.to_string(); let amount = amt.amount; @@ -119,8 +148,7 @@ impl TokenTransferExecutionContext for IbcStorage<'_, '_, '_> { outer.as_slice(), //signer PDA ); - Ok(anchor_spl::token::mint_to(cpi_ctx, amount_in_u64) - .unwrap()) + Ok(anchor_spl::token::mint_to(cpi_ctx, amount_in_u64).unwrap()) } fn burn_coins_execute( @@ -130,11 +158,11 @@ impl TokenTransferExecutionContext for IbcStorage<'_, '_, '_> { ) -> Result<(), TokenTransferError> { msg!( "Burning coins for account {}, trace path {}, base denom {}", - account.0, + account, amt.denom.trace_path, amt.denom.base_denom ); - let burner_id = account.0; + let burner_id = account.to_pubkey(); let base_denom = amt.denom.base_denom.to_string(); let amount = amt.amount; let amount_in_u64 = check_amount_overflow(amount)?; @@ -166,8 +194,7 @@ impl TokenTransferExecutionContext for IbcStorage<'_, '_, '_> { outer.as_slice(), //signer PDA ); - Ok(anchor_spl::token::burn(cpi_ctx, amount_in_u64) - .unwrap()) + Ok(anchor_spl::token::burn(cpi_ctx, amount_in_u64).unwrap()) } } @@ -239,8 +266,6 @@ fn get_account_info_from_key<'a, 'b>( /// Solana transfer only supports u64 so checking if the token transfer amount overflows. If it overflows we return an error else we return the converted u64 fn check_amount_overflow(amount: Amount) -> Result { u64::try_from(U256::from(amount)).map_err(|_| { - TokenTransferError::InvalidAmount( - FromDecStrErr::InvalidLength - ) + TokenTransferError::InvalidAmount(FromDecStrErr::InvalidLength) }) } From 8cfad4bbeacb897bc8edd8ea8f96dfc822a20a7c Mon Sep 17 00:00:00 2001 From: dhruvja Date: Fri, 3 Nov 2023 14:12:34 +0100 Subject: [PATCH 15/57] added from trait for pubkey --- .../solana-ibc/programs/solana-ibc/src/tests.rs | 12 ++++++++++++ .../programs/solana-ibc/src/transfer/impls.rs | 17 +++++++++-------- 2 files changed, 21 insertions(+), 8 deletions(-) diff --git a/solana/solana-ibc/programs/solana-ibc/src/tests.rs b/solana/solana-ibc/programs/solana-ibc/src/tests.rs index 26d00ee7..e1a45610 100644 --- a/solana/solana-ibc/programs/solana-ibc/src/tests.rs +++ b/solana/solana-ibc/programs/solana-ibc/src/tests.rs @@ -82,6 +82,12 @@ fn anchor_test_deliver() -> Result<()> { let packet_seeds = &[PACKET_SEED]; let packets = Pubkey::find_program_address(packet_seeds, &crate::ID).0; + /* + * + * Create New Mock Client + * + */ + let (mock_client_state, mock_cs_state) = create_mock_client_and_cs_state(); let _client_id = ClientId::new(mock_client_state.client_type(), 0).unwrap(); let message = make_message!( @@ -119,6 +125,12 @@ fn anchor_test_deliver() -> Result<()> { println!("This is solana storage account {:?}", solana_ibc_storage_account); + /* + * + * Create New Mock Connection Open Init + * + */ + let counter_party_client_id = ClientId::new(mock_client_state.client_type(), 1).unwrap(); diff --git a/solana/solana-ibc/programs/solana-ibc/src/transfer/impls.rs b/solana/solana-ibc/programs/solana-ibc/src/transfer/impls.rs index ca1dc6bf..e695b691 100644 --- a/solana/solana-ibc/programs/solana-ibc/src/transfer/impls.rs +++ b/solana/solana-ibc/programs/solana-ibc/src/transfer/impls.rs @@ -15,8 +15,7 @@ use uint::FromDecStrErr; // use crate::module_holder::IbcStorage<'_,'_>; use crate::{storage::IbcStorage, MINT_ESCROW_SEED}; -#[derive(Clone, PartialEq, Eq, derive_more::From, derive_more::Into)] -#[into(owned, ref, ref_mut)] +#[derive(Clone, PartialEq, Eq, derive_more::From)] pub struct AccountId(Pubkey); impl TryFrom for AccountId { @@ -51,8 +50,10 @@ impl core::fmt::Display for AccountId { } } -impl AccountId { - fn to_pubkey(&self) -> Pubkey { self.0 } +impl From<&AccountId> for Pubkey { + fn from(value: &AccountId) -> Self { + value.0 + } } impl TokenTransferExecutionContext for IbcStorage<'_, '_, '_> { @@ -70,8 +71,8 @@ impl TokenTransferExecutionContext for IbcStorage<'_, '_, '_> { amt.denom.trace_path, amt.denom.base_denom ); - let sender_id = from.to_pubkey(); - let receiver_id = to.to_pubkey(); + let sender_id = Pubkey::from(from); + let receiver_id = Pubkey::from(to); let base_denom = amt.denom.base_denom.to_string(); let amount = amt.amount; @@ -114,7 +115,7 @@ impl TokenTransferExecutionContext for IbcStorage<'_, '_, '_> { amt.denom.trace_path, amt.denom.base_denom ); - let receiver_id = account.to_pubkey(); + let receiver_id = Pubkey::from(account); let base_denom = amt.denom.base_denom.to_string(); let amount = amt.amount; @@ -162,7 +163,7 @@ impl TokenTransferExecutionContext for IbcStorage<'_, '_, '_> { amt.denom.trace_path, amt.denom.base_denom ); - let burner_id = account.to_pubkey(); + let burner_id = Pubkey::from(account); let base_denom = amt.denom.base_denom.to_string(); let amount = amt.amount; let amount_in_u64 = check_amount_overflow(amount)?; From 981c40b80e66fcb0cb21061a1dfb0312321ce820 Mon Sep 17 00:00:00 2001 From: dhruvja Date: Thu, 9 Nov 2023 09:11:16 +0100 Subject: [PATCH 16/57] added mocks for creating channel and connection --- .../solana-ibc/programs/solana-ibc/src/lib.rs | 82 ++++++++++++++++++- .../programs/solana-ibc/src/tests.rs | 56 ++++++++++--- .../programs/solana-ibc/src/transfer/impls.rs | 4 +- 3 files changed, 125 insertions(+), 17 deletions(-) diff --git a/solana/solana-ibc/programs/solana-ibc/src/lib.rs b/solana/solana-ibc/programs/solana-ibc/src/lib.rs index 504ea1e8..cfc66658 100644 --- a/solana/solana-ibc/programs/solana-ibc/src/lib.rs +++ b/solana/solana-ibc/programs/solana-ibc/src/lib.rs @@ -5,7 +5,17 @@ extern crate alloc; use anchor_lang::prelude::*; use borsh::{BorshDeserialize, BorshSerialize}; -use ibc::core::ics24_host::identifier::PortId; +use ibc::core::ics03_connection::connection::{ + ConnectionEnd, Counterparty, State as ConnState, +}; +use ibc::core::ics03_connection::version::Version; +use ibc::core::ics04_channel::{channel::{ + ChannelEnd, Counterparty as ChanCounterparty, Order, State as ChannelState, +}, Version as ChanVersion}; +use ibc::core::ics24_host::identifier::{ + ChannelId, ClientId, ConnectionId, PortId, +}; +use ibc::core::{ExecutionContext, ics24_host::path::{ConnectionPath, ChannelEndPath, SeqSendPath, SeqRecvPath}, ics23_commitment::commitment::CommitmentPrefix}; use ibc::core::router::{Module, ModuleId, Router}; const SOLANA_IBC_STORAGE_SEED: &[u8] = b"solana_ibc_storage"; @@ -31,9 +41,16 @@ mod trie_key; mod validation_context; // mod client_context; +#[cfg(feature = "mocks")] +const TEST: bool = true; +#[cfg(not(feature = "mocks"))] +const TEST: bool = false; + #[anchor_lang::program] pub mod solana_ibc { + + use super::*; pub fn deliver( @@ -84,6 +101,69 @@ pub mod solana_ibc { Ok(()) } + + /// This method is called to set up connection, channel and store the next sequence. Will panic if called without `[mocks]` feature + pub fn mock_deliver( + ctx: Context, + port_id: PortId, + commitment_prefix: CommitmentPrefix, + client_id: ClientId, + counterparty_client_id: ClientId, + ) -> Result<()> { + if !TEST { + panic!(); + } + let private: &mut storage::PrivateStorage = &mut ctx.accounts.storage; + msg!("This is private: {private:?}"); + let provable = storage::get_provable_from(&ctx.accounts.trie, "trie")?; + let packets: &mut IBCPackets = &mut ctx.accounts.packets; + let accounts = ctx.remaining_accounts; + + let mut store = storage::IbcStorage::new(storage::IbcStorageInner { + private, + provable, + packets, + accounts: accounts.to_vec(), + }); + + let connection_id = ConnectionId::new(0); + let delay_period = core::time::Duration::from_nanos(0); + let connection_counterparty = Counterparty::new( + counterparty_client_id, + Some(ConnectionId::new(1)), + commitment_prefix, + ); + let connection_end = ConnectionEnd::new( + ConnState::Open, + client_id, + connection_counterparty, + vec![Version::default()], + delay_period, + ).unwrap(); + + let counterparty = + ChanCounterparty::new(port_id.clone(), Some(ChannelId::new(1))); + let channel_end = ChannelEnd::new( + ChannelState::Open, + Order::Unordered, + counterparty, + vec![connection_id.clone()], + ChanVersion::new(ibc::applications::transfer::VERSION.to_string()), + ).unwrap(); + let channel_id = ChannelId::new(0); + + store.store_connection(&ConnectionPath(connection_id), connection_end).unwrap(); + store + .store_channel(&ChannelEndPath(port_id.clone(), channel_id.clone()), channel_end) + .unwrap(); + store + .store_next_sequence_send(&SeqSendPath(port_id.clone(), channel_id.clone()), 1.into()) + .unwrap(); + store + .store_next_sequence_recv(&SeqRecvPath(port_id, channel_id), 1.into()) + .unwrap(); + Ok(()) + } } #[derive(Accounts)] diff --git a/solana/solana-ibc/programs/solana-ibc/src/tests.rs b/solana/solana-ibc/programs/solana-ibc/src/tests.rs index e1a45610..69780601 100644 --- a/solana/solana-ibc/programs/solana-ibc/src/tests.rs +++ b/solana/solana-ibc/programs/solana-ibc/src/tests.rs @@ -16,7 +16,7 @@ use ibc::core::ics03_connection::connection::Counterparty; use ibc::core::ics03_connection::msgs::conn_open_init::MsgConnectionOpenInit; use ibc::core::ics03_connection::version::Version; use ibc::core::ics23_commitment::commitment::CommitmentPrefix; -use ibc::core::ics24_host::identifier::ClientId; +use ibc::core::ics24_host::identifier::{ClientId, PortId}; use ibc::mock::client_state::MockClientState; use ibc::mock::consensus_state::MockConsensusState; use ibc::mock::header::MockHeader; @@ -83,10 +83,10 @@ fn anchor_test_deliver() -> Result<()> { let packets = Pubkey::find_program_address(packet_seeds, &crate::ID).0; /* - * - * Create New Mock Client - * - */ + * + * Create New Mock Client + * + */ let (mock_client_state, mock_cs_state) = create_mock_client_and_cs_state(); let _client_id = ClientId::new(mock_client_state.client_type(), 0).unwrap(); @@ -126,10 +126,13 @@ fn anchor_test_deliver() -> Result<()> { println!("This is solana storage account {:?}", solana_ibc_storage_account); /* - * - * Create New Mock Connection Open Init - * - */ + * + * Create New Mock Connection Open Init + * + */ + + let client_id = ClientId::new(mock_client_state.client_type(), 0) + .unwrap(); let counter_party_client_id = ClientId::new(mock_client_state.client_type(), 1).unwrap(); @@ -139,13 +142,12 @@ fn anchor_test_deliver() -> Result<()> { let message = make_message!( MsgConnectionOpenInit { - client_id_on_a: ClientId::new(mock_client_state.client_type(), 0) - .unwrap(), + client_id_on_a: client_id.clone(), version: Some(Version::default()), counterparty: Counterparty::new( - counter_party_client_id, + counter_party_client_id.clone(), None, - commitment_prefix, + commitment_prefix.clone(), ), delay_period: Duration::from_secs(5), signer: ibc::Signer::from(authority.pubkey().to_string()), @@ -173,6 +175,34 @@ fn anchor_test_deliver() -> Result<()> { println!("signature for connection open init: {sig}"); + /* + * + * Setup mock connection and channel + * + */ + + let sig = program + .request() + .accounts(accounts::Deliver { + sender: authority.pubkey(), + storage: solana_ibc_storage, + trie, + system_program: system_program::ID, + packets, + }) + .args(instruction::MockDeliver { port_id: PortId::transfer(), commitment_prefix, client_id, counterparty_client_id: counter_party_client_id }) + .payer(authority.clone()) + .signer(&*authority) + .send_with_spinner_and_config(RpcSendTransactionConfig { + skip_preflight: true, + ..RpcSendTransactionConfig::default() + })?; + + println!("signature for setting up channel and connection with next seq: {sig}"); + + // Make sure all the accounts needed for transfer are ready ( mint, escrow etc.) + // Pass the instruction for transfer + Ok(()) } diff --git a/solana/solana-ibc/programs/solana-ibc/src/transfer/impls.rs b/solana/solana-ibc/programs/solana-ibc/src/transfer/impls.rs index e695b691..954d4a53 100644 --- a/solana/solana-ibc/programs/solana-ibc/src/transfer/impls.rs +++ b/solana/solana-ibc/programs/solana-ibc/src/transfer/impls.rs @@ -51,9 +51,7 @@ impl core::fmt::Display for AccountId { } impl From<&AccountId> for Pubkey { - fn from(value: &AccountId) -> Self { - value.0 - } + fn from(value: &AccountId) -> Self { value.0 } } impl TokenTransferExecutionContext for IbcStorage<'_, '_, '_> { From 56d477868bb07ea6b43b334841ea4c41ccaab5fe Mon Sep 17 00:00:00 2001 From: dhruvja Date: Wed, 15 Nov 2023 14:21:31 +0530 Subject: [PATCH 17/57] creating PDAs for token mint and escrow accounts for transfer --- .../solana-ibc/programs/solana-ibc/src/lib.rs | 102 ++++++++++++++++-- .../programs/solana-ibc/src/tests.rs | 69 +++++++++--- 2 files changed, 147 insertions(+), 24 deletions(-) diff --git a/solana/solana-ibc/programs/solana-ibc/src/lib.rs b/solana/solana-ibc/programs/solana-ibc/src/lib.rs index cfc66658..e21ba067 100644 --- a/solana/solana-ibc/programs/solana-ibc/src/lib.rs +++ b/solana/solana-ibc/programs/solana-ibc/src/lib.rs @@ -4,19 +4,26 @@ extern crate alloc; use anchor_lang::prelude::*; +use anchor_spl::associated_token::AssociatedToken; +use anchor_spl::token::{Mint, Token, TokenAccount}; use borsh::{BorshDeserialize, BorshSerialize}; use ibc::core::ics03_connection::connection::{ ConnectionEnd, Counterparty, State as ConnState, }; use ibc::core::ics03_connection::version::Version; -use ibc::core::ics04_channel::{channel::{ +use ibc::core::ics04_channel::channel::{ ChannelEnd, Counterparty as ChanCounterparty, Order, State as ChannelState, -}, Version as ChanVersion}; +}; +use ibc::core::ics04_channel::Version as ChanVersion; +use ibc::core::ics23_commitment::commitment::CommitmentPrefix; use ibc::core::ics24_host::identifier::{ ChannelId, ClientId, ConnectionId, PortId, }; -use ibc::core::{ExecutionContext, ics24_host::path::{ConnectionPath, ChannelEndPath, SeqSendPath, SeqRecvPath}, ics23_commitment::commitment::CommitmentPrefix}; +use ibc::core::ics24_host::path::{ + ChannelEndPath, ConnectionPath, SeqRecvPath, SeqSendPath, +}; use ibc::core::router::{Module, ModuleId, Router}; +use ibc::core::ExecutionContext; const SOLANA_IBC_STORAGE_SEED: &[u8] = b"solana_ibc_storage"; const MINT_ESCROW_SEED: &[u8] = b"mint_escrow"; @@ -46,10 +53,10 @@ const TEST: bool = true; #[cfg(not(feature = "mocks"))] const TEST: bool = false; - #[anchor_lang::program] pub mod solana_ibc { + use anchor_spl::token::MintTo; use super::*; @@ -104,8 +111,10 @@ pub mod solana_ibc { /// This method is called to set up connection, channel and store the next sequence. Will panic if called without `[mocks]` feature pub fn mock_deliver( - ctx: Context, + ctx: Context, port_id: PortId, + _channel_id: ChannelId, + _base_denom: String, commitment_prefix: CommitmentPrefix, client_id: ClientId, counterparty_client_id: ClientId, @@ -139,7 +148,8 @@ pub mod solana_ibc { connection_counterparty, vec![Version::default()], delay_period, - ).unwrap(); + ) + .unwrap(); let counterparty = ChanCounterparty::new(port_id.clone(), Some(ChannelId::new(1))); @@ -149,19 +159,50 @@ pub mod solana_ibc { counterparty, vec![connection_id.clone()], ChanVersion::new(ibc::applications::transfer::VERSION.to_string()), - ).unwrap(); + ) + .unwrap(); let channel_id = ChannelId::new(0); - store.store_connection(&ConnectionPath(connection_id), connection_end).unwrap(); store - .store_channel(&ChannelEndPath(port_id.clone(), channel_id.clone()), channel_end) + .store_connection(&ConnectionPath(connection_id), connection_end) .unwrap(); store - .store_next_sequence_send(&SeqSendPath(port_id.clone(), channel_id.clone()), 1.into()) + .store_channel( + &ChannelEndPath(port_id.clone(), channel_id.clone()), + channel_end, + ) .unwrap(); store - .store_next_sequence_recv(&SeqRecvPath(port_id, channel_id), 1.into()) + .store_next_sequence_send( + &SeqSendPath(port_id.clone(), channel_id.clone()), + 1.into(), + ) .unwrap(); + store + .store_next_sequence_recv( + &SeqRecvPath(port_id, channel_id), + 1.into(), + ) + .unwrap(); + + // Minting some tokens to the authority so that he can do the transfer + let bump_vector = + ctx.bumps.get("mint_authority").unwrap().to_le_bytes(); + let inner = vec![MINT_ESCROW_SEED, bump_vector.as_ref()]; + let outer = vec![inner.as_slice()]; + + // Mint some tokens to escrow account + let mint_instruction = MintTo { + mint: ctx.accounts.token_mint.to_account_info(), + to: ctx.accounts.sender_token_account.to_account_info(), + authority: ctx.accounts.mint_authority.to_account_info(), + }; + let cpi_ctx = CpiContext::new_with_signer( + ctx.accounts.token_program.to_account_info(), + mint_instruction, + outer.as_slice(), //signer PDA + ); + anchor_spl::token::mint_to(cpi_ctx, 10000000)?; Ok(()) } } @@ -189,6 +230,45 @@ pub struct Deliver<'info> { system_program: Program<'info, System>, } +#[derive(Accounts)] +#[instruction(port_id: PortId, channel_id: ChannelId, base_denom: String)] +pub struct MockDeliver<'info> { + #[account(mut)] + sender: Signer<'info>, + + /// The account holding private IBC storage. + #[account(init_if_needed, payer = sender, seeds = [SOLANA_IBC_STORAGE_SEED],bump, space = 10000)] + storage: Account<'info, storage::PrivateStorage>, + + /// The account holding provable IBC storage, i.e. the trie. + /// + /// CHECK: Account’s owner is checked by [`storage::get_provable_from`] + /// function. + #[account(init_if_needed, payer = sender, seeds = [TRIE_SEED], bump, space = 1000)] + trie: UncheckedAccount<'info>, + + /// The account holding packets. + #[account(init_if_needed, payer = sender, seeds = [PACKET_SEED], bump, space = 1000)] + packets: Box>, + + /// The below accounts are being created for testing purposes only. + /// In real, we would run conditionally create an escrow account when the channel is created. + /// And we could have another method that can create a mint given the denom. + #[account(init_if_needed, payer = sender, seeds = [MINT_ESCROW_SEED], bump, space = 100)] + /// CHECK: + mint_authority: UncheckedAccount<'info>, + #[account(init_if_needed, payer = sender, seeds = [base_denom.as_bytes().as_ref()], bump, mint::decimals = 6, mint::authority = mint_authority)] + token_mint: Account<'info, Mint>, + #[account(init_if_needed, payer = sender, seeds = [port_id.as_bytes().as_ref(), channel_id.as_bytes().as_ref()], bump, token::mint = token_mint, token::authority = sender)] + escrow_account: Box>, + #[account(init_if_needed, payer = sender, associated_token::mint = token_mint, associated_token::authority = sender)] + sender_token_account: Box>, + + associated_token_program: Program<'info, AssociatedToken>, + token_program: Program<'info, Token>, + system_program: Program<'info, System>, +} + /// Error returned when handling a request. #[derive(Clone, strum::AsRefStr, strum::EnumDiscriminants)] #[strum_discriminants(repr(u32))] diff --git a/solana/solana-ibc/programs/solana-ibc/src/tests.rs b/solana/solana-ibc/programs/solana-ibc/src/tests.rs index 69780601..261f8373 100644 --- a/solana/solana-ibc/programs/solana-ibc/src/tests.rs +++ b/solana/solana-ibc/programs/solana-ibc/src/tests.rs @@ -1,3 +1,4 @@ +use std::borrow::BorrowMut; use std::rc::Rc; use std::thread::sleep; use std::time::Duration; @@ -8,7 +9,11 @@ use anchor_client::solana_client::rpc_config::RpcSendTransactionConfig; use anchor_client::solana_sdk::commitment_config::CommitmentConfig; use anchor_client::solana_sdk::pubkey::Pubkey; use anchor_client::solana_sdk::signature::{Keypair, Signature, Signer}; +use anchor_client::solana_sdk::transaction::Transaction; use anchor_client::{Client, Cluster}; +use anchor_lang::solana_program::system_instruction; +use anchor_spl::associated_token::get_associated_token_address; +use anchor_spl::token::Mint; use anyhow::Result; use ibc::core::ics02_client::client_state::ClientStateCommon; use ibc::core::ics02_client::msgs::create_client::MsgCreateClient; @@ -16,7 +21,7 @@ use ibc::core::ics03_connection::connection::Counterparty; use ibc::core::ics03_connection::msgs::conn_open_init::MsgConnectionOpenInit; use ibc::core::ics03_connection::version::Version; use ibc::core::ics23_commitment::commitment::CommitmentPrefix; -use ibc::core::ics24_host::identifier::{ClientId, PortId}; +use ibc::core::ics24_host::identifier::{ChannelId, ClientId, PortId}; use ibc::mock::client_state::MockClientState; use ibc::mock::consensus_state::MockConsensusState; use ibc::mock::header::MockHeader; @@ -24,10 +29,12 @@ use ibc_proto::google::protobuf::Any; use crate::storage::PrivateStorage; use crate::{ - accounts, instruction, ID, PACKET_SEED, SOLANA_IBC_STORAGE_SEED, TRIE_SEED, + accounts, instruction, ID, MINT_ESCROW_SEED, PACKET_SEED, + SOLANA_IBC_STORAGE_SEED, TRIE_SEED, }; const IBC_TRIE_PREFIX: &[u8] = b"ibc/"; +const DENOM: &str = "transfer/channel-1/PICA"; fn airdrop(client: &RpcClient, account: Pubkey, lamports: u64) -> Signature { let balance_before = client.get_balance(&account).unwrap(); @@ -131,8 +138,7 @@ fn anchor_test_deliver() -> Result<()> { * */ - let client_id = ClientId::new(mock_client_state.client_type(), 0) - .unwrap(); + let client_id = ClientId::new(mock_client_state.client_type(), 0).unwrap(); let counter_party_client_id = ClientId::new(mock_client_state.client_type(), 1).unwrap(); @@ -176,21 +182,51 @@ fn anchor_test_deliver() -> Result<()> { println!("signature for connection open init: {sig}"); /* - * - * Setup mock connection and channel - * - */ + * + * Setup mock connection and channel + Steps before we proceed + - Create PDAs for the above keys, + - Create the token mint + - Get token account for receiver and sender + * + */ + + let port_id = PortId::transfer(); + let channel_id = ChannelId::new(0); - let sig = program + let seeds = [port_id.as_bytes().as_ref(), channel_id.as_bytes().as_ref()]; + let (escrow_account_key, _bump) = + Pubkey::find_program_address(&seeds, &crate::ID); + let (token_mint_key, _bump) = + Pubkey::find_program_address(&[DENOM.as_ref()], &crate::ID); + let (mint_authority_key, _bump) = + Pubkey::find_program_address(&[MINT_ESCROW_SEED], &crate::ID); + let sender_token_address = + get_associated_token_address(&authority.pubkey(), &token_mint_key); + + let sig = program .request() - .accounts(accounts::Deliver { + .accounts(accounts::MockDeliver { sender: authority.pubkey(), + sender_token_account: sender_token_address, storage: solana_ibc_storage, trie, + mint_authority: mint_authority_key, + escrow_account: escrow_account_key, + token_mint: token_mint_key, system_program: system_program::ID, + associated_token_program: anchor_spl::associated_token::ID, + token_program: anchor_spl::token::ID, packets, }) - .args(instruction::MockDeliver { port_id: PortId::transfer(), commitment_prefix, client_id, counterparty_client_id: counter_party_client_id }) + .args(instruction::MockDeliver { + port_id: port_id.clone(), + _channel_id: channel_id, + _base_denom: DENOM.to_string(), + commitment_prefix, + client_id, + counterparty_client_id: counter_party_client_id, + }) .payer(authority.clone()) .signer(&*authority) .send_with_spinner_and_config(RpcSendTransactionConfig { @@ -198,11 +234,18 @@ fn anchor_test_deliver() -> Result<()> { ..RpcSendTransactionConfig::default() })?; - println!("signature for setting up channel and connection with next seq: {sig}"); - + println!( + "signature for setting up channel and connection with next seq: {sig}" + ); + + let mint_info = sol_rpc_client.get_token_supply(&token_mint_key).unwrap(); + + println!("This is the mint information {:?}", mint_info); + // Make sure all the accounts needed for transfer are ready ( mint, escrow etc.) // Pass the instruction for transfer + Ok(()) } From d96ec9f1a074a2b07b1cfc6e000dfc0dbbfd1cc6 Mon Sep 17 00:00:00 2001 From: dhruvja Date: Thu, 16 Nov 2023 01:00:43 +0530 Subject: [PATCH 18/57] added remaining accounts and passing transfer packet --- Cargo.toml | 1 + .../solana-ibc/programs/solana-ibc/Cargo.toml | 1 + .../solana-ibc/programs/solana-ibc/src/lib.rs | 7 +- .../programs/solana-ibc/src/tests.rs | 171 +++++++++++++++++- 4 files changed, 172 insertions(+), 8 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index aac9406c..0fb2ecd8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -41,6 +41,7 @@ solana-client = "1.16.14" solana-program = "1.16.14" solana-sdk = "1.16.14" strum = { version = "0.25.0", default-features = false, features = ["derive"] } +spl-associated-token-account = "2.2.0" primitive-types = "0.12.2" lib = { path = "common/lib" } diff --git a/solana/solana-ibc/programs/solana-ibc/Cargo.toml b/solana/solana-ibc/programs/solana-ibc/Cargo.toml index 051ec0ba..7f46f845 100644 --- a/solana/solana-ibc/programs/solana-ibc/Cargo.toml +++ b/solana/solana-ibc/programs/solana-ibc/Cargo.toml @@ -26,6 +26,7 @@ serde_json.workspace = true primitive-types.workspace = true strum.workspace = true derive_more.workspace = true +spl-associated-token-account.workspace = true lib.workspace = true memory.workspace = true diff --git a/solana/solana-ibc/programs/solana-ibc/src/lib.rs b/solana/solana-ibc/programs/solana-ibc/src/lib.rs index e21ba067..d0db9ba5 100644 --- a/solana/solana-ibc/programs/solana-ibc/src/lib.rs +++ b/solana/solana-ibc/programs/solana-ibc/src/lib.rs @@ -73,6 +73,8 @@ pub mod solana_ibc { let packets: &mut IBCPackets = &mut ctx.accounts.packets; let accounts = ctx.remaining_accounts; + msg!("These are remaining accounts {:?}", accounts); + let mut store = storage::IbcStorage::new(storage::IbcStorageInner { private, provable, @@ -203,6 +205,7 @@ pub mod solana_ibc { outer.as_slice(), //signer PDA ); anchor_spl::token::mint_to(cpi_ctx, 10000000)?; + Ok(()) } } @@ -251,8 +254,8 @@ pub struct MockDeliver<'info> { #[account(init_if_needed, payer = sender, seeds = [PACKET_SEED], bump, space = 1000)] packets: Box>, - /// The below accounts are being created for testing purposes only. - /// In real, we would run conditionally create an escrow account when the channel is created. + /// The below accounts are being created for testing purposes only. + /// In real, we would run conditionally create an escrow account when the channel is created. /// And we could have another method that can create a mint given the denom. #[account(init_if_needed, payer = sender, seeds = [MINT_ESCROW_SEED], bump, space = 100)] /// CHECK: diff --git a/solana/solana-ibc/programs/solana-ibc/src/tests.rs b/solana/solana-ibc/programs/solana-ibc/src/tests.rs index 261f8373..d4610bc9 100644 --- a/solana/solana-ibc/programs/solana-ibc/src/tests.rs +++ b/solana/solana-ibc/programs/solana-ibc/src/tests.rs @@ -1,5 +1,5 @@ -use std::borrow::BorrowMut; use std::rc::Rc; +use std::str::FromStr; use std::thread::sleep; use std::time::Duration; @@ -10,21 +10,32 @@ use anchor_client::solana_sdk::commitment_config::CommitmentConfig; use anchor_client::solana_sdk::pubkey::Pubkey; use anchor_client::solana_sdk::signature::{Keypair, Signature, Signer}; use anchor_client::solana_sdk::transaction::Transaction; +use anchor_lang::ToAccountMetas; +use anchor_lang::solana_program::instruction::AccountMeta; +use spl_associated_token_account::instruction::create_associated_token_account; use anchor_client::{Client, Cluster}; -use anchor_lang::solana_program::system_instruction; -use anchor_spl::associated_token::get_associated_token_address; -use anchor_spl::token::Mint; +use anchor_lang::prelude::borsh; +use anchor_spl::associated_token::{get_associated_token_address, self}; use anyhow::Result; +use ibc::applications::transfer::packet::PacketData; +use ibc::applications::transfer::{Amount, BaseCoin, BaseDenom, Coin}; use ibc::core::ics02_client::client_state::ClientStateCommon; use ibc::core::ics02_client::msgs::create_client::MsgCreateClient; use ibc::core::ics03_connection::connection::Counterparty; use ibc::core::ics03_connection::msgs::conn_open_init::MsgConnectionOpenInit; use ibc::core::ics03_connection::version::Version; -use ibc::core::ics23_commitment::commitment::CommitmentPrefix; +use ibc::core::ics04_channel::msgs::MsgRecvPacket; +use ibc::core::ics04_channel::packet::Packet; +use ibc::core::ics04_channel::timeout::TimeoutHeight; +use ibc::core::ics23_commitment::commitment::{ + CommitmentPrefix, CommitmentProofBytes, +}; use ibc::core::ics24_host::identifier::{ChannelId, ClientId, PortId}; +use ibc::core::timestamp::Timestamp; use ibc::mock::client_state::MockClientState; use ibc::mock::consensus_state::MockConsensusState; use ibc::mock::header::MockHeader; +use ibc::Height; use ibc_proto::google::protobuf::Any; use crate::storage::PrivateStorage; @@ -63,6 +74,56 @@ macro_rules! make_message { }} } +pub struct DeliverWithRemainingAccounts { + sender: Pubkey, + storage: Pubkey, + trie: Pubkey, + packets: Pubkey, + system_program: Pubkey, + remaining_accounts: Vec +} + +impl ToAccountMetas for DeliverWithRemainingAccounts { + fn to_account_metas(&self, is_signer: Option) -> Vec { + let mut accounts = Vec::new(); + accounts.push(AccountMeta{ + pubkey: self.sender, + is_signer: true, + is_writable: true, + }); + accounts.push(AccountMeta{ + pubkey: self.storage, + is_signer: false, + is_writable: true, + }); + accounts.push(AccountMeta{ + pubkey: self.trie, + is_signer: false, + is_writable: true, + }); + accounts.push(AccountMeta{ + pubkey: self.packets, + is_signer: false, + is_writable: true, + }); + accounts.push(AccountMeta{ + pubkey: self.system_program, + is_signer: false, + is_writable: false, + }); + + self.remaining_accounts.iter().for_each(|&account| { + accounts.push(AccountMeta{ + pubkey: account, + is_signer: false, + is_writable: false, + }) + }); + + accounts + } +} + #[test] #[ignore = "Requires local validator to run"] fn anchor_test_deliver() -> Result<()> { @@ -221,7 +282,7 @@ fn anchor_test_deliver() -> Result<()> { }) .args(instruction::MockDeliver { port_id: port_id.clone(), - _channel_id: channel_id, + _channel_id: channel_id.clone(), _base_denom: DENOM.to_string(), commitment_prefix, client_id, @@ -241,10 +302,108 @@ fn anchor_test_deliver() -> Result<()> { let mint_info = sol_rpc_client.get_token_supply(&token_mint_key).unwrap(); println!("This is the mint information {:?}", mint_info); + // Retrieve and validate state + let solana_ibc_storage_account: PrivateStorage = + program.account(solana_ibc_storage).unwrap(); + + println!("This is solana storage account {:?}", solana_ibc_storage_account); // Make sure all the accounts needed for transfer are ready ( mint, escrow etc.) // Pass the instruction for transfer + // Create a new receier with a token account + let receiver = Keypair::new(); + let ix = Transaction::new_signed_with_payer( + &[create_associated_token_account(&authority.pubkey(), &receiver.pubkey(), &token_mint_key, &anchor_spl::token::ID)], + Some(&authority.pubkey()), + &[&*authority], + sol_rpc_client.get_latest_blockhash().unwrap() + ); + let tx = sol_rpc_client.send_transaction_with_config(&ix, RpcSendTransactionConfig { + skip_preflight: true, + ..RpcSendTransactionConfig::default() + }).unwrap(); + let receiver_token_address = + get_associated_token_address(&receiver.pubkey(), &token_mint_key); + + println!("this is token account creation signature {}", tx); + + let base_denom: BaseDenom = BaseDenom::from_str(DENOM).unwrap(); + let token: BaseCoin = + Coin { denom: base_denom, amount: Amount::from(1000000) }; + + let packet_data = PacketData { + token: token.into(), + sender: ibc::Signer::from(sender_token_address.to_string()), // Should be a token account + receiver: ibc::Signer::from(receiver.try_pubkey().unwrap().to_string()), // Should be a token account + memo: String::from("My first tx").into(), + }; + + let serialized_data = borsh::to_vec(&packet_data).unwrap(); + + let packet = Packet { + seq_on_a: 1.into(), + port_id_on_a: port_id.clone(), + chan_id_on_a: channel_id, + port_id_on_b: port_id, + chan_id_on_b: ChannelId::new(1), + data: serialized_data.clone(), + timeout_height_on_b: TimeoutHeight::Never, + timeout_timestamp_on_b: Timestamp::none(), + }; + + let message = make_message!( + MsgRecvPacket { + packet, + proof_commitment_on_a: CommitmentProofBytes::try_from(serialized_data) + .unwrap(), + proof_height_on_a: Height::new(0, 1).unwrap(), + signer: ibc::Signer::from(authority.pubkey().to_string()) + }, + ibc::core::ics04_channel::msgs::PacketMsg::Recv, + ibc::core::MsgEnvelope::Packet, + ); + + /* + The remaining accounts consists of the following accounts + - sender token account + - receiver token account + - token mint + - escrow account ( token account ) + - mint authority + - token program + */ + + let remaining_accounts = vec![ + sender_token_address, + receiver_token_address, + token_mint_key, + escrow_account_key, + mint_authority_key, + anchor_spl::token::ID, + ]; + + let sig = program + .request() + .accounts(DeliverWithRemainingAccounts { + sender: authority.pubkey(), + storage: solana_ibc_storage, + trie, + system_program: system_program::ID, + packets, + remaining_accounts + }) + .args(instruction::Deliver { message }) + .payer(authority.clone()) + .signer(&*authority) + .send_with_spinner_and_config(RpcSendTransactionConfig { + skip_preflight: true, + ..RpcSendTransactionConfig::default() + })?; // ? gives us the log messages on the why the tx did fail ( better than unwrap ) + + println!("signature for transfer packet: {sig}"); + + Ok(()) } From c7c61cf12a0438e659b740478a77611ca7abd403 Mon Sep 17 00:00:00 2001 From: dhruvja Date: Thu, 16 Nov 2023 12:45:50 +0530 Subject: [PATCH 19/57] storing connection and channel for of both client a and b --- .../solana-ibc/programs/solana-ibc/src/lib.rs | 74 +++++++++++++++---- .../programs/solana-ibc/src/tests.rs | 58 +++++++++------ .../solana-ibc/src/validation_context.rs | 1 + 3 files changed, 97 insertions(+), 36 deletions(-) diff --git a/solana/solana-ibc/programs/solana-ibc/src/lib.rs b/solana/solana-ibc/programs/solana-ibc/src/lib.rs index d0db9ba5..e4b4aa91 100644 --- a/solana/solana-ibc/programs/solana-ibc/src/lib.rs +++ b/solana/solana-ibc/programs/solana-ibc/src/lib.rs @@ -137,16 +137,25 @@ pub mod solana_ibc { accounts: accounts.to_vec(), }); - let connection_id = ConnectionId::new(0); + let connection_id_on_a = ConnectionId::new(0); + let connection_id_on_b = ConnectionId::new(1); let delay_period = core::time::Duration::from_nanos(0); let connection_counterparty = Counterparty::new( - counterparty_client_id, - Some(ConnectionId::new(1)), + counterparty_client_id.clone(), + Some(connection_id_on_b.clone()), commitment_prefix, ); - let connection_end = ConnectionEnd::new( + let connection_end_on_a = ConnectionEnd::new( ConnState::Open, client_id, + connection_counterparty.clone(), + vec![Version::default()], + delay_period, + ) + .unwrap(); + let connection_end_on_b = ConnectionEnd::new( + ConnState::Open, + counterparty_client_id, connection_counterparty, vec![Version::default()], delay_period, @@ -154,35 +163,74 @@ pub mod solana_ibc { .unwrap(); let counterparty = - ChanCounterparty::new(port_id.clone(), Some(ChannelId::new(1))); - let channel_end = ChannelEnd::new( + ChanCounterparty::new(port_id.clone(), Some(ChannelId::new(0))); + let channel_end_on_a = ChannelEnd::new( + ChannelState::Open, + Order::Unordered, + counterparty.clone(), + vec![connection_id_on_a.clone()], + ChanVersion::new(ibc::applications::transfer::VERSION.to_string()), + ) + .unwrap(); + let channel_end_on_b = ChannelEnd::new( ChannelState::Open, Order::Unordered, counterparty, - vec![connection_id.clone()], + vec![connection_id_on_b.clone()], ChanVersion::new(ibc::applications::transfer::VERSION.to_string()), ) .unwrap(); - let channel_id = ChannelId::new(0); + let channel_id_on_a = ChannelId::new(0); + let channel_id_on_b = ChannelId::new(1); + // For Client on Chain A store - .store_connection(&ConnectionPath(connection_id), connection_end) + .store_connection( + &ConnectionPath(connection_id_on_a), + connection_end_on_a, + ) + .unwrap(); + store + .store_channel( + &ChannelEndPath(port_id.clone(), channel_id_on_a.clone()), + channel_end_on_a, + ) + .unwrap(); + store + .store_next_sequence_send( + &SeqSendPath(port_id.clone(), channel_id_on_a.clone()), + 1.into(), + ) + .unwrap(); + store + .store_next_sequence_recv( + &SeqRecvPath(port_id.clone(), channel_id_on_a), + 1.into(), + ) + .unwrap(); + + // For Client on chain b + store + .store_connection( + &ConnectionPath(connection_id_on_b), + connection_end_on_b, + ) .unwrap(); store .store_channel( - &ChannelEndPath(port_id.clone(), channel_id.clone()), - channel_end, + &ChannelEndPath(port_id.clone(), channel_id_on_b.clone()), + channel_end_on_b, ) .unwrap(); store .store_next_sequence_send( - &SeqSendPath(port_id.clone(), channel_id.clone()), + &SeqSendPath(port_id.clone(), channel_id_on_b.clone()), 1.into(), ) .unwrap(); store .store_next_sequence_recv( - &SeqRecvPath(port_id, channel_id), + &SeqRecvPath(port_id, channel_id_on_b), 1.into(), ) .unwrap(); diff --git a/solana/solana-ibc/programs/solana-ibc/src/tests.rs b/solana/solana-ibc/programs/solana-ibc/src/tests.rs index d4610bc9..78d3dc51 100644 --- a/solana/solana-ibc/programs/solana-ibc/src/tests.rs +++ b/solana/solana-ibc/programs/solana-ibc/src/tests.rs @@ -10,12 +10,11 @@ use anchor_client::solana_sdk::commitment_config::CommitmentConfig; use anchor_client::solana_sdk::pubkey::Pubkey; use anchor_client::solana_sdk::signature::{Keypair, Signature, Signer}; use anchor_client::solana_sdk::transaction::Transaction; -use anchor_lang::ToAccountMetas; -use anchor_lang::solana_program::instruction::AccountMeta; -use spl_associated_token_account::instruction::create_associated_token_account; use anchor_client::{Client, Cluster}; use anchor_lang::prelude::borsh; -use anchor_spl::associated_token::{get_associated_token_address, self}; +use anchor_lang::solana_program::instruction::AccountMeta; +use anchor_lang::ToAccountMetas; +use anchor_spl::associated_token::{self, get_associated_token_address}; use anyhow::Result; use ibc::applications::transfer::packet::PacketData; use ibc::applications::transfer::{Amount, BaseCoin, BaseDenom, Coin}; @@ -37,6 +36,7 @@ use ibc::mock::consensus_state::MockConsensusState; use ibc::mock::header::MockHeader; use ibc::Height; use ibc_proto::google::protobuf::Any; +use spl_associated_token_account::instruction::create_associated_token_account; use crate::storage::PrivateStorage; use crate::{ @@ -80,40 +80,43 @@ pub struct DeliverWithRemainingAccounts { trie: Pubkey, packets: Pubkey, system_program: Pubkey, - remaining_accounts: Vec + remaining_accounts: Vec, } impl ToAccountMetas for DeliverWithRemainingAccounts { - fn to_account_metas(&self, is_signer: Option) -> Vec { + fn to_account_metas( + &self, + is_signer: Option, + ) -> Vec { let mut accounts = Vec::new(); - accounts.push(AccountMeta{ + accounts.push(AccountMeta { pubkey: self.sender, is_signer: true, is_writable: true, }); - accounts.push(AccountMeta{ + accounts.push(AccountMeta { pubkey: self.storage, is_signer: false, is_writable: true, }); - accounts.push(AccountMeta{ + accounts.push(AccountMeta { pubkey: self.trie, is_signer: false, is_writable: true, }); - accounts.push(AccountMeta{ + accounts.push(AccountMeta { pubkey: self.packets, is_signer: false, is_writable: true, }); - accounts.push(AccountMeta{ + accounts.push(AccountMeta { pubkey: self.system_program, is_signer: false, is_writable: false, }); self.remaining_accounts.iter().for_each(|&account| { - accounts.push(AccountMeta{ + accounts.push(AccountMeta { pubkey: account, is_signer: false, is_writable: false, @@ -314,15 +317,22 @@ fn anchor_test_deliver() -> Result<()> { // Create a new receier with a token account let receiver = Keypair::new(); let ix = Transaction::new_signed_with_payer( - &[create_associated_token_account(&authority.pubkey(), &receiver.pubkey(), &token_mint_key, &anchor_spl::token::ID)], + &[create_associated_token_account( + &authority.pubkey(), + &receiver.pubkey(), + &token_mint_key, + &anchor_spl::token::ID, + )], Some(&authority.pubkey()), &[&*authority], - sol_rpc_client.get_latest_blockhash().unwrap() + sol_rpc_client.get_latest_blockhash().unwrap(), ); - let tx = sol_rpc_client.send_transaction_with_config(&ix, RpcSendTransactionConfig { - skip_preflight: true, - ..RpcSendTransactionConfig::default() - }).unwrap(); + let tx = sol_rpc_client + .send_transaction_with_config(&ix, RpcSendTransactionConfig { + skip_preflight: true, + ..RpcSendTransactionConfig::default() + }) + .unwrap(); let receiver_token_address = get_associated_token_address(&receiver.pubkey(), &token_mint_key); @@ -338,7 +348,7 @@ fn anchor_test_deliver() -> Result<()> { receiver: ibc::Signer::from(receiver.try_pubkey().unwrap().to_string()), // Should be a token account memo: String::from("My first tx").into(), }; - + let serialized_data = borsh::to_vec(&packet_data).unwrap(); let packet = Packet { @@ -355,8 +365,10 @@ fn anchor_test_deliver() -> Result<()> { let message = make_message!( MsgRecvPacket { packet, - proof_commitment_on_a: CommitmentProofBytes::try_from(serialized_data) - .unwrap(), + proof_commitment_on_a: CommitmentProofBytes::try_from( + serialized_data + ) + .unwrap(), proof_height_on_a: Height::new(0, 1).unwrap(), signer: ibc::Signer::from(authority.pubkey().to_string()) }, @@ -391,7 +403,7 @@ fn anchor_test_deliver() -> Result<()> { trie, system_program: system_program::ID, packets, - remaining_accounts + remaining_accounts, }) .args(instruction::Deliver { message }) .payer(authority.clone()) @@ -401,7 +413,7 @@ fn anchor_test_deliver() -> Result<()> { ..RpcSendTransactionConfig::default() })?; // ? gives us the log messages on the why the tx did fail ( better than unwrap ) - println!("signature for transfer packet: {sig}"); + println!("signature for transfer packet: {sig}"); diff --git a/solana/solana-ibc/programs/solana-ibc/src/validation_context.rs b/solana/solana-ibc/programs/solana-ibc/src/validation_context.rs index e179561c..6fde08e7 100644 --- a/solana/solana-ibc/programs/solana-ibc/src/validation_context.rs +++ b/solana/solana-ibc/programs/solana-ibc/src/validation_context.rs @@ -2,6 +2,7 @@ use std::str::FromStr; use std::time::Duration; use anchor_lang::prelude::{borsh, Clock, Pubkey, SolanaSysvar}; +use anchor_lang::solana_program::msg; use ibc::core::ics02_client::error::ClientError; use ibc::core::ics03_connection::connection::ConnectionEnd; use ibc::core::ics03_connection::error::ConnectionError; From 88488b06c727ecc3ce9bfdd7b29e372fb9eb3089 Mon Sep 17 00:00:00 2001 From: dhruvja Date: Thu, 16 Nov 2023 19:25:12 +0530 Subject: [PATCH 20/57] rm redunant code and fix accounts struct --- .../solana-ibc/programs/solana-ibc/src/lib.rs | 47 ++-------- .../programs/solana-ibc/src/tests.rs | 91 +++++++++---------- .../solana-ibc/src/validation_context.rs | 2 + 3 files changed, 54 insertions(+), 86 deletions(-) diff --git a/solana/solana-ibc/programs/solana-ibc/src/lib.rs b/solana/solana-ibc/programs/solana-ibc/src/lib.rs index b8cb0340..ea5c2f1f 100644 --- a/solana/solana-ibc/programs/solana-ibc/src/lib.rs +++ b/solana/solana-ibc/programs/solana-ibc/src/lib.rs @@ -6,6 +6,7 @@ extern crate alloc; use anchor_lang::prelude::*; +use anchor_lang::solana_program; use anchor_spl::associated_token::AssociatedToken; use anchor_spl::token::{Mint, Token, TokenAccount}; use borsh::{BorshDeserialize, BorshSerialize}; @@ -25,10 +26,7 @@ use ibc::core::ics24_host::path::{ ChannelEndPath, ConnectionPath, SeqRecvPath, SeqSendPath, }; use ibc::core::router::{Module, ModuleId, Router}; -use ibc::core::ExecutionContext; - -use anchor_lang::solana_program; -use ibc::core::MsgEnvelope; +use ibc::core::{ExecutionContext, MsgEnvelope}; const CHAIN_SEED: &[u8] = b"chain"; const PACKET_SEED: &[u8] = b"packet"; @@ -228,7 +226,7 @@ pub mod solana_ibc { ); let connection_end_on_a = ConnectionEnd::new( ConnState::Open, - client_id, + client_id.clone(), connection_counterparty.clone(), vec![Version::default()], delay_period, @@ -236,7 +234,7 @@ pub mod solana_ibc { .unwrap(); let connection_end_on_b = ConnectionEnd::new( ConnState::Open, - counterparty_client_id, + client_id, connection_counterparty, vec![Version::default()], delay_period, @@ -403,9 +401,9 @@ pub struct Deliver<'info> { #[account(init_if_needed, payer = sender, seeds = [PACKET_SEED], bump, space = 1000)] packets: Account<'info, IBCPackets>, - /// The guest blockchain data. - #[account(init_if_needed, payer = sender, seeds = [CHAIN_SEED], bump, space = 10000)] - chain: Box>, + // /// The guest blockchain data. + // #[account(init_if_needed, payer = sender, seeds = [CHAIN_SEED], bump, space = 10000)] + // chain: Box>, system_program: Program<'info, System>, } @@ -449,37 +447,6 @@ pub struct MockDeliver<'info> { system_program: Program<'info, System>, } -/// Error returned when handling a request. -#[derive(Clone, strum::AsRefStr, strum::EnumDiscriminants)] -#[strum_discriminants(repr(u32))] -pub enum Error<'a> { - RouterError(&'a ibc::core::RouterError), -} - -impl Error<'_> { - pub fn name(&self) -> String { self.as_ref().into() } -} - -impl core::fmt::Display for Error<'_> { - fn fmt(&self, fmtr: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - match self { - Self::RouterError(err) => write!(fmtr, "{err}"), - } - } -} - -impl From> for u32 { - fn from(err: Error<'_>) -> u32 { - let code = ErrorDiscriminants::from(err) as u32; - anchor_lang::error::ERROR_CODE_OFFSET + code - } -} - -#[event] -pub struct EmitIBCEvent { - pub ibc_event: Vec, -} - impl Router for storage::IbcStorage<'_, '_, '_> { // fn get_route(&self, module_id: &ModuleId) -> Option<&dyn Module> { diff --git a/solana/solana-ibc/programs/solana-ibc/src/tests.rs b/solana/solana-ibc/programs/solana-ibc/src/tests.rs index e1cd506b..da661ea0 100644 --- a/solana/solana-ibc/programs/solana-ibc/src/tests.rs +++ b/solana/solana-ibc/programs/solana-ibc/src/tests.rs @@ -39,9 +39,7 @@ use ibc_proto::google::protobuf::Any; use spl_associated_token_account::instruction::create_associated_token_account; use crate::storage::PrivateStorage; -use crate::{ - accounts, instruction, MINT_ESCROW_SEED, -}; +use crate::{accounts, instruction, MINT_ESCROW_SEED}; const IBC_TRIE_PREFIX: &[u8] = b"ibc/"; const DENOM: &str = "transfer/channel-1/PICA"; @@ -78,7 +76,7 @@ pub struct DeliverWithRemainingAccounts { storage: Pubkey, trie: Pubkey, packets: Pubkey, - chain: Pubkey, + // chain: Pubkey, system_program: Pubkey, remaining_accounts: Vec, } @@ -88,48 +86,49 @@ impl ToAccountMetas for DeliverWithRemainingAccounts { &self, _is_signer: Option, ) -> Vec { - let mut accounts = Vec::new(); - accounts.push(AccountMeta { - pubkey: self.sender, - is_signer: true, - is_writable: true, - }); - accounts.push(AccountMeta { - pubkey: self.storage, - is_signer: false, - is_writable: true, - }); - accounts.push(AccountMeta { - pubkey: self.trie, - is_signer: false, - is_writable: true, - }); - accounts.push(AccountMeta { - pubkey: self.packets, - is_signer: false, - is_writable: true, - }); - accounts.push(AccountMeta { - pubkey: self.chain, - is_signer: false, - is_writable: true, - }); - accounts.push(AccountMeta { - pubkey: self.system_program, - is_signer: false, - is_writable: false, - }); - - - self.remaining_accounts.iter().for_each(|&account| { - accounts.push(AccountMeta { - pubkey: account, + let accounts = [ + AccountMeta { + pubkey: self.sender, + is_signer: true, + is_writable: true, + }, + AccountMeta { + pubkey: self.storage, + is_signer: false, + is_writable: true, + }, + AccountMeta { + pubkey: self.trie, + is_signer: false, + is_writable: true, + }, + AccountMeta { + pubkey: self.packets, + is_signer: false, + is_writable: true, + }, + // AccountMeta { + // pubkey: self.chain, + // is_signer: false, + // is_writable: true, + // }, + AccountMeta { + pubkey: self.system_program, is_signer: false, is_writable: false, - }) - }); + }, + ]; - accounts + + let remaining = self + .remaining_accounts + .iter() + .map(|&account| AccountMeta { + pubkey: account, + is_signer: false, + is_writable: false, + }); + accounts.into_iter().chain(remaining).collect::>() } } @@ -188,7 +187,7 @@ fn anchor_test_deliver() -> Result<()> { storage, trie, packets, - chain, + // chain, system_program: system_program::ID, }) .args(instruction::Deliver { message }) @@ -244,7 +243,7 @@ fn anchor_test_deliver() -> Result<()> { storage, trie, packets, - chain: chain.clone(), + // chain: chain.clone(), system_program: system_program::ID, }) .args(instruction::Deliver { message }) @@ -415,7 +414,7 @@ fn anchor_test_deliver() -> Result<()> { trie, system_program: system_program::ID, packets, - chain, + // chain, remaining_accounts, }) .args(instruction::Deliver { message }) diff --git a/solana/solana-ibc/programs/solana-ibc/src/validation_context.rs b/solana/solana-ibc/programs/solana-ibc/src/validation_context.rs index 591f260d..da6cfdf5 100644 --- a/solana/solana-ibc/programs/solana-ibc/src/validation_context.rs +++ b/solana/solana-ibc/programs/solana-ibc/src/validation_context.rs @@ -2,6 +2,7 @@ use std::str::FromStr; use std::time::Duration; use anchor_lang::prelude::{borsh, Clock, Pubkey, SolanaSysvar}; +use anchor_lang::solana_program::msg; use ibc::core::ics02_client::error::ClientError; use ibc::core::ics03_connection::connection::ConnectionEnd; use ibc::core::ics03_connection::error::ConnectionError; @@ -39,6 +40,7 @@ impl ValidationContext for IbcStorage<'_, '_, '_> { &self, client_id: &ClientId, ) -> Result { + msg!("This is client id {:?}", client_id); deserialise( self.borrow().private.clients.get(client_id.as_str()), || ClientError::ClientStateNotFound { From 3e5b53e75f8f2ac2fd7dbe5571a700996c424e63 Mon Sep 17 00:00:00 2001 From: dhruvja Date: Thu, 16 Nov 2023 22:35:07 +0530 Subject: [PATCH 21/57] reallocating data in mock deliver method --- solana/solana-ibc/programs/solana-ibc/src/lib.rs | 4 +--- .../solana-ibc/programs/solana-ibc/src/validation_context.rs | 2 -- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/solana/solana-ibc/programs/solana-ibc/src/lib.rs b/solana/solana-ibc/programs/solana-ibc/src/lib.rs index ea5c2f1f..9d1b05df 100644 --- a/solana/solana-ibc/programs/solana-ibc/src/lib.rs +++ b/solana/solana-ibc/programs/solana-ibc/src/lib.rs @@ -149,8 +149,6 @@ pub mod solana_ibc { let packets: &mut IBCPackets = &mut ctx.accounts.packets; let accounts = ctx.remaining_accounts; - msg!("These are remaining accounts {:?}", accounts); - // Before anything else, try generating a new guest block. However, if // that fails it’s not an error condition. We do this at the beginning // of any request. @@ -415,7 +413,7 @@ pub struct MockDeliver<'info> { sender: Signer<'info>, /// The account holding private IBC storage. - #[account(init_if_needed, payer = sender, seeds = [SOLANA_IBC_STORAGE_SEED],bump, space = 10000)] + #[account(mut, seeds = [SOLANA_IBC_STORAGE_SEED],bump, realloc = 10000, realloc::payer = sender, realloc::zero = false)] storage: Account<'info, storage::PrivateStorage>, /// The account holding provable IBC storage, i.e. the trie. diff --git a/solana/solana-ibc/programs/solana-ibc/src/validation_context.rs b/solana/solana-ibc/programs/solana-ibc/src/validation_context.rs index da6cfdf5..591f260d 100644 --- a/solana/solana-ibc/programs/solana-ibc/src/validation_context.rs +++ b/solana/solana-ibc/programs/solana-ibc/src/validation_context.rs @@ -2,7 +2,6 @@ use std::str::FromStr; use std::time::Duration; use anchor_lang::prelude::{borsh, Clock, Pubkey, SolanaSysvar}; -use anchor_lang::solana_program::msg; use ibc::core::ics02_client::error::ClientError; use ibc::core::ics03_connection::connection::ConnectionEnd; use ibc::core::ics03_connection::error::ConnectionError; @@ -40,7 +39,6 @@ impl ValidationContext for IbcStorage<'_, '_, '_> { &self, client_id: &ClientId, ) -> Result { - msg!("This is client id {:?}", client_id); deserialise( self.borrow().private.clients.get(client_id.as_str()), || ClientError::ClientStateNotFound { From a4e682b5e6cc64745315a72054e37d1d49415dfe Mon Sep 17 00:00:00 2001 From: dhruvja Date: Fri, 17 Nov 2023 00:38:47 +0530 Subject: [PATCH 22/57] using base denom instead of the complete denom for token mint seed --- .../solana-ibc/programs/solana-ibc/src/lib.rs | 20 +++++++-- .../programs/solana-ibc/src/tests.rs | 42 ++++++++++++------- .../programs/solana-ibc/src/transfer/impls.rs | 11 ++--- 3 files changed, 50 insertions(+), 23 deletions(-) diff --git a/solana/solana-ibc/programs/solana-ibc/src/lib.rs b/solana/solana-ibc/programs/solana-ibc/src/lib.rs index aff4d323..7340219b 100644 --- a/solana/solana-ibc/programs/solana-ibc/src/lib.rs +++ b/solana/solana-ibc/programs/solana-ibc/src/lib.rs @@ -65,7 +65,9 @@ const TEST: bool = false; pub mod solana_ibc { use anchor_spl::token::MintTo; - use ibc::{core::{ics02_client::ClientExecutionContext, timestamp::Timestamp}, Height}; + use ibc::core::ics02_client::ClientExecutionContext; + use ibc::core::timestamp::Timestamp; + use ibc::Height; use super::*; @@ -222,8 +224,19 @@ pub mod solana_ibc { // Store update time since its not called during mocks let clock = Clock::get().unwrap(); let current_timestamp = clock.unix_timestamp as u64; - let _ = store.store_update_time(client_id.clone(), Height::new(private_storage.height.0, private_storage.height.1).unwrap(), Timestamp::from_nanoseconds(current_timestamp).unwrap()); - let _ = store.store_update_height(client_id.clone(), Height::new(private_storage.height.0, private_storage.height.1).unwrap(), Height::new(private_storage.height.0, private_storage.height.1).unwrap()); + let _ = store.store_update_time( + client_id.clone(), + Height::new(private_storage.height.0, private_storage.height.1) + .unwrap(), + Timestamp::from_nanoseconds(current_timestamp).unwrap(), + ); + let _ = store.store_update_height( + client_id.clone(), + Height::new(private_storage.height.0, private_storage.height.1) + .unwrap(), + Height::new(private_storage.height.0, private_storage.height.1) + .unwrap(), + ); let connection_id_on_a = ConnectionId::new(0); let connection_id_on_b = ConnectionId::new(1); @@ -413,7 +426,6 @@ pub struct Deliver<'info> { // /// The guest blockchain data. // #[account(init_if_needed, payer = sender, seeds = [CHAIN_SEED], bump, space = 10000)] // chain: Box>, - system_program: Program<'info, System>, } diff --git a/solana/solana-ibc/programs/solana-ibc/src/tests.rs b/solana/solana-ibc/programs/solana-ibc/src/tests.rs index da661ea0..6469adbf 100644 --- a/solana/solana-ibc/programs/solana-ibc/src/tests.rs +++ b/solana/solana-ibc/programs/solana-ibc/src/tests.rs @@ -11,7 +11,6 @@ use anchor_client::solana_sdk::pubkey::Pubkey; use anchor_client::solana_sdk::signature::{Keypair, Signature, Signer}; use anchor_client::solana_sdk::transaction::Transaction; use anchor_client::{Client, Cluster}; -use anchor_lang::prelude::borsh; use anchor_lang::solana_program::instruction::AccountMeta; use anchor_lang::ToAccountMetas; use anchor_spl::associated_token::get_associated_token_address; @@ -43,6 +42,7 @@ use crate::{accounts, instruction, MINT_ESCROW_SEED}; const IBC_TRIE_PREFIX: &[u8] = b"ibc/"; const DENOM: &str = "transfer/channel-1/PICA"; +const BASE_DENOM: &str = "PICA"; fn airdrop(client: &RpcClient, account: Pubkey, lamports: u64) -> Signature { let balance_before = client.get_balance(&account).unwrap(); @@ -120,14 +120,26 @@ impl ToAccountMetas for DeliverWithRemainingAccounts { ]; - let remaining = self - .remaining_accounts - .iter() - .map(|&account| AccountMeta { - pubkey: account, - is_signer: false, - is_writable: false, - }); + let mut x = 0; + let remaining = + self.remaining_accounts.iter().map(|&account| { + x += 1; + if x > 6 { + AccountMeta { + pubkey: account, + is_signer: false, + is_writable: false, + } + } else { + AccountMeta { + pubkey: account, + is_signer: false, + is_writable: true, + } + } + + }); + accounts.into_iter().chain(remaining).collect::>() } } @@ -273,7 +285,7 @@ fn anchor_test_deliver() -> Result<()> { let (escrow_account_key, _bump) = Pubkey::find_program_address(&seeds, &crate::ID); let (token_mint_key, _bump) = - Pubkey::find_program_address(&[DENOM.as_ref()], &crate::ID); + Pubkey::find_program_address(&[BASE_DENOM.as_ref()], &crate::ID); let (mint_authority_key, _bump) = Pubkey::find_program_address(&[MINT_ESCROW_SEED], &crate::ID); let sender_token_address = @@ -297,7 +309,7 @@ fn anchor_test_deliver() -> Result<()> { .args(instruction::MockDeliver { port_id: port_id.clone(), _channel_id: channel_id.clone(), - _base_denom: DENOM.to_string(), + _base_denom: BASE_DENOM.to_string(), commitment_prefix, client_id, counterparty_client_id: counter_party_client_id, @@ -320,7 +332,7 @@ fn anchor_test_deliver() -> Result<()> { let solana_ibc_storage_account: PrivateStorage = program.account(storage).unwrap(); - println!("This is solana storage account {:?}", solana_ibc_storage_account); + // println!("This is solana storage account {:?}", solana_ibc_storage_account); // Make sure all the accounts needed for transfer are ready ( mint, escrow etc.) // Pass the instruction for transfer @@ -356,11 +368,11 @@ fn anchor_test_deliver() -> Result<()> { let packet_data = PacketData { token: token.into(), sender: ibc::Signer::from(sender_token_address.to_string()), // Should be a token account - receiver: ibc::Signer::from(receiver.try_pubkey().unwrap().to_string()), // Should be a token account + receiver: ibc::Signer::from(receiver_token_address.to_string()), // Should be a token account memo: String::from("My first tx").into(), }; - let serialized_data = borsh::to_vec(&packet_data).unwrap(); + let serialized_data = serde_json::to_vec(&packet_data).unwrap(); let packet = Packet { seq_on_a: 1.into(), @@ -406,6 +418,8 @@ fn anchor_test_deliver() -> Result<()> { anchor_spl::token::ID, ]; + println!("These are remaining accounts {:?}", remaining_accounts); + let sig = program .request() .accounts(DeliverWithRemainingAccounts { diff --git a/solana/solana-ibc/programs/solana-ibc/src/transfer/impls.rs b/solana/solana-ibc/programs/solana-ibc/src/transfer/impls.rs index 954d4a53..5838d0d9 100644 --- a/solana/solana-ibc/programs/solana-ibc/src/transfer/impls.rs +++ b/solana/solana-ibc/programs/solana-ibc/src/transfer/impls.rs @@ -108,20 +108,21 @@ impl TokenTransferExecutionContext for IbcStorage<'_, '_, '_> { amt: &PrefixedCoin, ) -> Result<(), TokenTransferError> { msg!( - "Minting coins for account {}, trace path {}, base denom {}", + "Minting coins for account {:?}, trace path {}, base denom {}", account, amt.denom.trace_path, amt.denom.base_denom ); + msg!("This should appear before"); let receiver_id = Pubkey::from(account); let base_denom = amt.denom.base_denom.to_string(); let amount = amt.amount; let amount_in_u64 = check_amount_overflow(amount)?; - let (token_mint_key, bump) = + let (token_mint_key, _bump) = Pubkey::find_program_address(&[base_denom.as_ref()], &crate::ID); - let (mint_authority_key, _bump) = + let (mint_authority_key, mint_authority_bump) = Pubkey::find_program_address(&[MINT_ESCROW_SEED], &crate::ID); let store = self.borrow(); let accounts = &store.accounts; @@ -131,8 +132,8 @@ impl TokenTransferExecutionContext for IbcStorage<'_, '_, '_> { let mint_authority = get_account_info_from_key(accounts, mint_authority_key)?; - let bump_vector = bump.to_le_bytes(); - let inner = vec![base_denom.as_ref(), bump_vector.as_ref()]; + let bump_vector = mint_authority_bump.to_le_bytes(); + let inner = vec![MINT_ESCROW_SEED.as_ref(), bump_vector.as_ref()]; let outer = vec![inner.as_slice()]; // Below is the actual instruction that we are going to send to the Token program. From 80668b45456ad55d4eadc78acf9497a5d6c0b953 Mon Sep 17 00:00:00 2001 From: dhruvja Date: Fri, 17 Nov 2023 01:59:58 +0530 Subject: [PATCH 23/57] commented excessive logging --- .../solana-ibc/src/execution_context.rs | 8 ++--- .../solana-ibc/programs/solana-ibc/src/lib.rs | 20 ++++++------ .../programs/solana-ibc/src/tests.rs | 31 ++++++++++++------- 3 files changed, 35 insertions(+), 24 deletions(-) diff --git a/solana/solana-ibc/programs/solana-ibc/src/execution_context.rs b/solana/solana-ibc/programs/solana-ibc/src/execution_context.rs index b86279c4..ab0fe421 100644 --- a/solana/solana-ibc/programs/solana-ibc/src/execution_context.rs +++ b/solana/solana-ibc/programs/solana-ibc/src/execution_context.rs @@ -133,7 +133,7 @@ impl ClientExecutionContext for IbcStorage<'_, '_, '_> { height: Height, timestamp: Timestamp, ) -> Result<(), ContextError> { - msg!("store_update_time({}, {}, {})", client_id, height, timestamp); + // msg!("store_update_time({}, {}, {})", client_id, height, timestamp); self.borrow_mut() .private .client_processed_times @@ -152,7 +152,7 @@ impl ClientExecutionContext for IbcStorage<'_, '_, '_> { height: Height, host_height: Height, ) -> Result<(), ContextError> { - msg!("store_update_height({}, {}, {})", client_id, height, host_height); + // msg!("store_update_height({}, {}, {})", client_id, height, host_height); self.borrow_mut() .private .client_processed_heights @@ -326,7 +326,7 @@ impl ExecutionContext for IbcStorage<'_, '_, '_> { path: &SeqSendPath, seq: Sequence, ) -> Result { - msg!("store_next_sequence_send: path: {}, seq: {}", path, seq); + msg!("store_next_sequence_send"); self.borrow_mut().store_next_sequence( path.into(), crate::storage::SequenceTripleIdx::Send, @@ -339,7 +339,7 @@ impl ExecutionContext for IbcStorage<'_, '_, '_> { path: &SeqRecvPath, seq: Sequence, ) -> Result { - msg!("store_next_sequence_recv: path: {}, seq: {}", path, seq); + msg!("store_next_sequence_recv"); self.borrow_mut().store_next_sequence( path.into(), crate::storage::SequenceTripleIdx::Recv, diff --git a/solana/solana-ibc/programs/solana-ibc/src/lib.rs b/solana/solana-ibc/programs/solana-ibc/src/lib.rs index 7340219b..ba0a80c6 100644 --- a/solana/solana-ibc/programs/solana-ibc/src/lib.rs +++ b/solana/solana-ibc/programs/solana-ibc/src/lib.rs @@ -143,14 +143,11 @@ pub mod solana_ibc { ctx: Context, message: ibc::core::MsgEnvelope, ) -> Result<()> { - let x = 5; - let y = 6; - msg!("This is test {x} {}", y); - msg!("Called deliver method: {:?}", message); + // msg!("Called deliver method: {:?}", message); let _sender = ctx.accounts.sender.to_account_info(); let private: &mut storage::PrivateStorage = &mut ctx.accounts.storage; - msg!("This is private: {:?}", private); + // msg!("This is private: {:?}", private); let provable = storage::get_provable_from(&ctx.accounts.trie, "trie")?; let packets: &mut IBCPackets = &mut ctx.accounts.packets; let accounts = ctx.remaining_accounts; @@ -187,7 +184,7 @@ pub mod solana_ibc { // which means try_into_inner will succeed. let inner = store.try_into_inner().unwrap(); - msg!("This is final structure {:?}", inner.private); + // msg!("This is final structure {:?}", inner.private); // msg!("this is length {}", TrieKey::ClientState{ client_id: String::from("hello")}.into()); @@ -209,7 +206,7 @@ pub mod solana_ibc { } let private: &mut storage::PrivateStorage = &mut ctx.accounts.storage; let private_storage = private.clone(); - msg!("This is private: {private:?}"); + // msg!("This is private: {private:?}"); let provable = storage::get_provable_from(&ctx.accounts.trie, "trie")?; let packets: &mut IBCPackets = &mut ctx.accounts.packets; let accounts = ctx.remaining_accounts; @@ -435,9 +432,12 @@ pub struct MockDeliver<'info> { #[account(mut)] sender: Signer<'info>, + /// CHECK: + receiver: AccountInfo<'info>, + /// The account holding private IBC storage. #[account(mut, seeds = [SOLANA_IBC_STORAGE_SEED],bump, realloc = 10000, realloc::payer = sender, realloc::zero = false)] - storage: Account<'info, storage::PrivateStorage>, + storage: Box>, /// The account holding provable IBC storage, i.e. the trie. /// @@ -457,11 +457,13 @@ pub struct MockDeliver<'info> { /// CHECK: mint_authority: UncheckedAccount<'info>, #[account(init_if_needed, payer = sender, seeds = [base_denom.as_bytes().as_ref()], bump, mint::decimals = 6, mint::authority = mint_authority)] - token_mint: Account<'info, Mint>, + token_mint: Box>, #[account(init_if_needed, payer = sender, seeds = [port_id.as_bytes().as_ref(), channel_id.as_bytes().as_ref()], bump, token::mint = token_mint, token::authority = sender)] escrow_account: Box>, #[account(init_if_needed, payer = sender, associated_token::mint = token_mint, associated_token::authority = sender)] sender_token_account: Box>, + #[account(init_if_needed, payer = sender, associated_token::mint = token_mint, associated_token::authority = receiver)] + receiver_token_account: Box>, associated_token_program: Program<'info, AssociatedToken>, token_program: Program<'info, Token>, diff --git a/solana/solana-ibc/programs/solana-ibc/src/tests.rs b/solana/solana-ibc/programs/solana-ibc/src/tests.rs index 6469adbf..07aac966 100644 --- a/solana/solana-ibc/programs/solana-ibc/src/tests.rs +++ b/solana/solana-ibc/programs/solana-ibc/src/tests.rs @@ -124,19 +124,19 @@ impl ToAccountMetas for DeliverWithRemainingAccounts { let remaining = self.remaining_accounts.iter().map(|&account| { x += 1; - if x > 6 { - AccountMeta { - pubkey: account, - is_signer: false, - is_writable: false, - } - } else { + // if x == 2 { + // AccountMeta { + // pubkey: account, + // is_signer: false, + // is_writable: , + // } + // } else { AccountMeta { pubkey: account, is_signer: false, is_writable: true, } - } + // } }); @@ -281,6 +281,8 @@ fn anchor_test_deliver() -> Result<()> { let port_id = PortId::transfer(); let channel_id = ChannelId::new(0); + let receiver = Keypair::new(); + let seeds = [port_id.as_bytes().as_ref(), channel_id.as_bytes().as_ref()]; let (escrow_account_key, _bump) = Pubkey::find_program_address(&seeds, &crate::ID); @@ -290,12 +292,17 @@ fn anchor_test_deliver() -> Result<()> { Pubkey::find_program_address(&[MINT_ESCROW_SEED], &crate::ID); let sender_token_address = get_associated_token_address(&authority.pubkey(), &token_mint_key); + let receiver_token_address = + get_associated_token_address(&receiver.pubkey(), &token_mint_key); + let sig = program .request() .accounts(accounts::MockDeliver { sender: authority.pubkey(), sender_token_account: sender_token_address, + receiver: receiver.pubkey(), + receiver_token_account: receiver_token_address, storage, trie, mint_authority: mint_authority_key, @@ -338,7 +345,7 @@ fn anchor_test_deliver() -> Result<()> { // Pass the instruction for transfer // Create a new receier with a token account - let receiver = Keypair::new(); + let ix = Transaction::new_signed_with_payer( &[create_associated_token_account( &authority.pubkey(), @@ -356,8 +363,7 @@ fn anchor_test_deliver() -> Result<()> { ..RpcSendTransactionConfig::default() }) .unwrap(); - let receiver_token_address = - get_associated_token_address(&receiver.pubkey(), &token_mint_key); + println!("this is token account creation signature {}", tx); @@ -441,6 +447,9 @@ fn anchor_test_deliver() -> Result<()> { println!("signature for transfer packet: {sig}"); + let mint_info = sol_rpc_client.get_token_supply(&token_mint_key).unwrap(); + + println!("This is the mint information {:?}", mint_info); Ok(()) From a865302b40a1433204dda88accfb6d89521c1446 Mon Sep 17 00:00:00 2001 From: Michal Nazarewicz Date: Fri, 17 Nov 2023 14:16:58 +0100 Subject: [PATCH 24/57] unwrap --- solana/solana-ibc/programs/solana-ibc/src/lib.rs | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/solana/solana-ibc/programs/solana-ibc/src/lib.rs b/solana/solana-ibc/programs/solana-ibc/src/lib.rs index 93b22d2c..63d2a88d 100644 --- a/solana/solana-ibc/programs/solana-ibc/src/lib.rs +++ b/solana/solana-ibc/programs/solana-ibc/src/lib.rs @@ -225,16 +225,12 @@ pub mod solana_ibc { }); // Store update time since its not called during mocks - let _ = store.store_update_time( - client_id.clone(), - host_height, - host_timestamp, - ); - let _ = store.store_update_height( - client_id.clone(), - host_height, - host_height, - ); + store + .store_update_time(client_id.clone(), host_height, host_timestamp) + .unwrap(); + store + .store_update_height(client_id.clone(), host_height, host_height) + .unwrap(); let connection_id_on_a = ConnectionId::new(0); let connection_id_on_b = ConnectionId::new(1); From b9d71d6cc61dece76e2e61bb12de1a9f3302d863 Mon Sep 17 00:00:00 2001 From: dhruvja Date: Sat, 18 Nov 2023 20:51:15 +0530 Subject: [PATCH 25/57] increase trie storage to 10kb and using latest height from client state --- .../solana-ibc/src/execution_context.rs | 8 +- .../solana-ibc/programs/solana-ibc/src/lib.rs | 344 ++++++++++-------- .../programs/solana-ibc/src/tests.rs | 21 +- .../solana-ibc/src/validation_context.rs | 2 + 4 files changed, 202 insertions(+), 173 deletions(-) diff --git a/solana/solana-ibc/programs/solana-ibc/src/execution_context.rs b/solana/solana-ibc/programs/solana-ibc/src/execution_context.rs index 1285fbcb..cbc07dd8 100644 --- a/solana/solana-ibc/programs/solana-ibc/src/execution_context.rs +++ b/solana/solana-ibc/programs/solana-ibc/src/execution_context.rs @@ -122,12 +122,14 @@ impl ClientExecutionContext for IbcStorage<'_, '_, '_> { timestamp: Timestamp, ) -> Result<(), ContextError> { // msg!("store_update_time({}, {}, {})", client_id, height, timestamp); - self.borrow_mut() + let mut store = self.borrow_mut(); + store .private .client_processed_times .entry(client_id.to_string()) .or_default() .insert(height, timestamp.nanoseconds()); + store.private.height = height; Ok(()) } @@ -138,12 +140,14 @@ impl ClientExecutionContext for IbcStorage<'_, '_, '_> { host_height: Height, ) -> Result<(), ContextError> { // msg!("store_update_height({}, {}, {})", client_id, height, host_height); - self.borrow_mut() + let mut store = self.borrow_mut(); + store .private .client_processed_heights .entry(client_id.to_string()) .or_default() .insert(height, host_height); + store.private.height = height; Ok(()) } } diff --git a/solana/solana-ibc/programs/solana-ibc/src/lib.rs b/solana/solana-ibc/programs/solana-ibc/src/lib.rs index 63d2a88d..e9474c65 100644 --- a/solana/solana-ibc/programs/solana-ibc/src/lib.rs +++ b/solana/solana-ibc/programs/solana-ibc/src/lib.rs @@ -8,25 +8,39 @@ extern crate alloc; use anchor_lang::prelude::*; use anchor_lang::solana_program; use anchor_spl::associated_token::AssociatedToken; +#[cfg(feature = "mocks")] +use anchor_spl::token::MintTo; use anchor_spl::token::{Mint, Token, TokenAccount}; use borsh::BorshDeserialize; +#[cfg(feature = "mocks")] use ibc::core::ics03_connection::connection::{ ConnectionEnd, Counterparty, State as ConnState, }; +#[cfg(feature = "mocks")] use ibc::core::ics03_connection::version::Version; +#[cfg(feature = "mocks")] use ibc::core::ics04_channel::channel::{ ChannelEnd, Counterparty as ChanCounterparty, Order, State as ChannelState, }; +#[cfg(feature = "mocks")] use ibc::core::ics04_channel::Version as ChanVersion; use ibc::core::ics23_commitment::commitment::CommitmentPrefix; -use ibc::core::ics24_host::identifier::{ - ChannelId, ClientId, ConnectionId, PortId, -}; +#[cfg(feature = "mocks")] +use ibc::core::ics24_host::identifier::ConnectionId; +use ibc::core::ics24_host::identifier::{ChannelId, ClientId, PortId}; +#[cfg(feature = "mocks")] use ibc::core::ics24_host::path::{ ChannelEndPath, ConnectionPath, SeqRecvPath, SeqSendPath, }; use ibc::core::router::{Module, ModuleId, Router}; -use ibc::core::{ExecutionContext, MsgEnvelope}; +use ibc::core::MsgEnvelope; +#[cfg(feature = "mocks")] +use ibc::core::ExecutionContext; +#[cfg(feature = "mocks")] +use ibc::{ + core::{ics02_client::ClientExecutionContext, ValidationContext}, + mock::client_state::MockClientState, +}; const CHAIN_SEED: &[u8] = b"chain"; const PACKET_SEED: &[u8] = b"packet"; @@ -57,15 +71,9 @@ mod trie_key; mod validation_context; // mod client_context; -#[cfg(feature = "mocks")] -const TEST: bool = true; -#[cfg(not(feature = "mocks"))] -const TEST: bool = false; - #[anchor_lang::program] pub mod solana_ibc { - use anchor_spl::token::MintTo; - use ibc::core::ics02_client::ClientExecutionContext; + use super::*; @@ -191,164 +199,188 @@ pub mod solana_ibc { } /// This method is called to set up connection, channel and store the next sequence. Will panic if called without `[mocks]` feature + #[allow(unused_variables)] pub fn mock_deliver( ctx: Context, port_id: PortId, - _channel_id: ChannelId, - _base_denom: String, + channel_id: ChannelId, + base_denom: String, commitment_prefix: CommitmentPrefix, client_id: ClientId, counterparty_client_id: ClientId, ) -> Result<()> { - if !TEST { - panic!(); - } - let private: &mut storage::PrivateStorage = &mut ctx.accounts.storage; - // msg!("This is private: {private:?}"); - let provable = storage::get_provable_from(&ctx.accounts.trie, "trie")?; - let packets: &mut IBCPackets = &mut ctx.accounts.packets; - let accounts = ctx.remaining_accounts; - - let host_head = host::Head::get()?; - let (host_timestamp, host_height) = host_head - .ibc_timestamp() - .and_then(|ts| host_head.ibc_height().map(|h| (ts, h))) - .map_err(error::Error::from) - .map_err(|err| error!((&err)))?; - - let mut store = storage::IbcStorage::new(storage::IbcStorageInner { - private, - provable, - packets, - accounts: accounts.to_vec(), - host_head, - }); - - // Store update time since its not called during mocks - store - .store_update_time(client_id.clone(), host_height, host_timestamp) - .unwrap(); - store - .store_update_height(client_id.clone(), host_height, host_height) - .unwrap(); + #[cfg(feature = "mocks")] + { + let private: &mut storage::PrivateStorage = + &mut ctx.accounts.storage; + // msg!("This is private: {private:?}"); + let provable = + storage::get_provable_from(&ctx.accounts.trie, "trie")?; + let packets: &mut IBCPackets = &mut ctx.accounts.packets; + let accounts = ctx.remaining_accounts; + + let host_head = host::Head::get()?; + let (host_timestamp, host_height) = host_head + .ibc_timestamp() + .and_then(|ts| host_head.ibc_height().map(|h| (ts, h))) + .map_err(error::Error::from) + .map_err(|err| error!((&err)))?; - let connection_id_on_a = ConnectionId::new(0); - let connection_id_on_b = ConnectionId::new(1); - let delay_period = core::time::Duration::from_nanos(0); - let connection_counterparty = Counterparty::new( - counterparty_client_id.clone(), - Some(connection_id_on_b.clone()), - commitment_prefix, - ); - let connection_end_on_a = ConnectionEnd::new( - ConnState::Open, - client_id.clone(), - connection_counterparty.clone(), - vec![Version::default()], - delay_period, - ) - .unwrap(); - let connection_end_on_b = ConnectionEnd::new( - ConnState::Open, - client_id, - connection_counterparty, - vec![Version::default()], - delay_period, - ) - .unwrap(); - - let counterparty = - ChanCounterparty::new(port_id.clone(), Some(ChannelId::new(0))); - let channel_end_on_a = ChannelEnd::new( - ChannelState::Open, - Order::Unordered, - counterparty.clone(), - vec![connection_id_on_a.clone()], - ChanVersion::new(ibc::applications::transfer::VERSION.to_string()), - ) - .unwrap(); - let channel_end_on_b = ChannelEnd::new( - ChannelState::Open, - Order::Unordered, - counterparty, - vec![connection_id_on_b.clone()], - ChanVersion::new(ibc::applications::transfer::VERSION.to_string()), - ) - .unwrap(); - let channel_id_on_a = ChannelId::new(0); - let channel_id_on_b = ChannelId::new(1); - - // For Client on Chain A - store - .store_connection( - &ConnectionPath(connection_id_on_a), - connection_end_on_a, + let mut store = + storage::IbcStorage::new(storage::IbcStorageInner { + private, + provable, + packets, + accounts: accounts.to_vec(), + host_head, + }); + + let any_client_state = store.client_state(&client_id).unwrap(); + let client_state: MockClientState = match any_client_state { + client_state::AnyClientState::Tendermint(_) => { + panic!("Only for mocks") + } + client_state::AnyClientState::Mock(mock) => mock, + }; + + + // Store update time since its not called during mocks + store + .store_update_time( + client_id.clone(), + client_state.latest_height(), + host_timestamp, + ) + .unwrap(); + store + .store_update_height( + client_id.clone(), + client_state.latest_height(), + host_height, + ) + .unwrap(); + + let connection_id_on_a = ConnectionId::new(0); + let connection_id_on_b = ConnectionId::new(1); + let delay_period = core::time::Duration::from_nanos(0); + let connection_counterparty = Counterparty::new( + counterparty_client_id.clone(), + Some(connection_id_on_b.clone()), + commitment_prefix, + ); + let connection_end_on_a = ConnectionEnd::new( + ConnState::Open, + client_id.clone(), + connection_counterparty.clone(), + vec![Version::default()], + delay_period, ) .unwrap(); - store - .store_channel( - &ChannelEndPath(port_id.clone(), channel_id_on_a.clone()), - channel_end_on_a, - ) - .unwrap(); - store - .store_next_sequence_send( - &SeqSendPath(port_id.clone(), channel_id_on_a.clone()), - 1.into(), - ) - .unwrap(); - store - .store_next_sequence_recv( - &SeqRecvPath(port_id.clone(), channel_id_on_a), - 1.into(), + let connection_end_on_b = ConnectionEnd::new( + ConnState::Open, + client_id, + connection_counterparty, + vec![Version::default()], + delay_period, ) .unwrap(); - // For Client on chain b - store - .store_connection( - &ConnectionPath(connection_id_on_b), - connection_end_on_b, - ) - .unwrap(); - store - .store_channel( - &ChannelEndPath(port_id.clone(), channel_id_on_b.clone()), - channel_end_on_b, + let counterparty = + ChanCounterparty::new(port_id.clone(), Some(ChannelId::new(0))); + let channel_end_on_a = ChannelEnd::new( + ChannelState::Open, + Order::Unordered, + counterparty.clone(), + vec![connection_id_on_a.clone()], + ChanVersion::new( + ibc::applications::transfer::VERSION.to_string(), + ), ) .unwrap(); - store - .store_next_sequence_send( - &SeqSendPath(port_id.clone(), channel_id_on_b.clone()), - 1.into(), + let channel_end_on_b = ChannelEnd::new( + ChannelState::Open, + Order::Unordered, + counterparty, + vec![connection_id_on_b.clone()], + ChanVersion::new( + ibc::applications::transfer::VERSION.to_string(), + ), ) .unwrap(); - store - .store_next_sequence_recv( - &SeqRecvPath(port_id, channel_id_on_b), - 1.into(), - ) - .unwrap(); - - // Minting some tokens to the authority so that he can do the transfer - let bump_vector = - ctx.bumps.get("mint_authority").unwrap().to_le_bytes(); - let inner = vec![MINT_ESCROW_SEED, bump_vector.as_ref()]; - let outer = vec![inner.as_slice()]; - - // Mint some tokens to escrow account - let mint_instruction = MintTo { - mint: ctx.accounts.token_mint.to_account_info(), - to: ctx.accounts.sender_token_account.to_account_info(), - authority: ctx.accounts.mint_authority.to_account_info(), - }; - let cpi_ctx = CpiContext::new_with_signer( - ctx.accounts.token_program.to_account_info(), - mint_instruction, - outer.as_slice(), //signer PDA - ); - anchor_spl::token::mint_to(cpi_ctx, 10000000)?; - + let channel_id_on_a = ChannelId::new(0); + let channel_id_on_b = ChannelId::new(1); + + // For Client on Chain A + store + .store_connection( + &ConnectionPath(connection_id_on_a), + connection_end_on_a, + ) + .unwrap(); + store + .store_channel( + &ChannelEndPath(port_id.clone(), channel_id_on_a.clone()), + channel_end_on_a, + ) + .unwrap(); + store + .store_next_sequence_send( + &SeqSendPath(port_id.clone(), channel_id_on_a.clone()), + 1.into(), + ) + .unwrap(); + store + .store_next_sequence_recv( + &SeqRecvPath(port_id.clone(), channel_id_on_a), + 1.into(), + ) + .unwrap(); + + // For Client on chain b + store + .store_connection( + &ConnectionPath(connection_id_on_b), + connection_end_on_b, + ) + .unwrap(); + store + .store_channel( + &ChannelEndPath(port_id.clone(), channel_id_on_b.clone()), + channel_end_on_b, + ) + .unwrap(); + store + .store_next_sequence_send( + &SeqSendPath(port_id.clone(), channel_id_on_b.clone()), + 1.into(), + ) + .unwrap(); + store + .store_next_sequence_recv( + &SeqRecvPath(port_id, channel_id_on_b), + 1.into(), + ) + .unwrap(); + + // Minting some tokens to the authority so that he can do the transfer + let bump_vector = + ctx.bumps.get("mint_authority").unwrap().to_le_bytes(); + let inner = vec![MINT_ESCROW_SEED, bump_vector.as_ref()]; + let outer = vec![inner.as_slice()]; + + // Mint some tokens to escrow account + let mint_instruction = MintTo { + mint: ctx.accounts.token_mint.to_account_info(), + to: ctx.accounts.sender_token_account.to_account_info(), + authority: ctx.accounts.mint_authority.to_account_info(), + }; + let cpi_ctx = CpiContext::new_with_signer( + ctx.accounts.token_program.to_account_info(), + mint_instruction, + outer.as_slice(), //signer PDA + ); + anchor_spl::token::mint_to(cpi_ctx, 10000000)?; + } Ok(()) } } @@ -367,7 +399,7 @@ pub struct Chain<'info> { /// /// CHECK: Account’s owner is checked by [`storage::get_provable_from`] /// function. - #[account(init_if_needed, payer = sender, seeds = [TRIE_SEED], bump, space = 1000)] + #[account(init_if_needed, payer = sender, seeds = [TRIE_SEED], bump, space = 10000)] trie: UncheckedAccount<'info>, system_program: Program<'info, System>, @@ -387,7 +419,7 @@ pub struct ChainWithVerifier<'info> { /// /// CHECK: Account’s owner is checked by [`storage::get_provable_from`] /// function. - #[account(init_if_needed, payer = sender, seeds = [TRIE_SEED], bump, space = 1000)] + #[account(init_if_needed, payer = sender, seeds = [TRIE_SEED], bump, space = 10000)] trie: UncheckedAccount<'info>, #[account(address = solana_program::sysvar::instructions::ID)] @@ -410,7 +442,7 @@ pub struct Deliver<'info> { /// /// CHECK: Account’s owner is checked by [`storage::get_provable_from`] /// function. - #[account(init_if_needed, payer = sender, seeds = [TRIE_SEED], bump, space = 1000)] + #[account(init_if_needed, payer = sender, seeds = [TRIE_SEED], bump, space = 10000)] trie: UncheckedAccount<'info>, /// The account holding packets. @@ -440,7 +472,7 @@ pub struct MockDeliver<'info> { /// /// CHECK: Account’s owner is checked by [`storage::get_provable_from`] /// function. - #[account(init_if_needed, payer = sender, seeds = [TRIE_SEED], bump, space = 1000)] + #[account(init_if_needed, payer = sender, seeds = [TRIE_SEED], bump, space = 10000)] trie: UncheckedAccount<'info>, /// The account holding packets. diff --git a/solana/solana-ibc/programs/solana-ibc/src/tests.rs b/solana/solana-ibc/programs/solana-ibc/src/tests.rs index 913eabed..1119a9d5 100644 --- a/solana/solana-ibc/programs/solana-ibc/src/tests.rs +++ b/solana/solana-ibc/programs/solana-ibc/src/tests.rs @@ -33,7 +33,6 @@ use ibc::core::timestamp::Timestamp; use ibc::mock::client_state::MockClientState; use ibc::mock::consensus_state::MockConsensusState; use ibc::mock::header::MockHeader; -use ibc::Height; use ibc_proto::google::protobuf::Any; use spl_associated_token_account::instruction::create_associated_token_account; @@ -120,18 +119,8 @@ impl ToAccountMetas for DeliverWithRemainingAccounts { ]; - let mut x = 0; let remaining = self.remaining_accounts.iter().map(|&account| { - x += 1; - // if x == 2 { - // AccountMeta { - // pubkey: account, - // is_signer: false, - // is_writable: , - // } - // } else { AccountMeta { pubkey: account, is_signer: false, is_writable: true } - // } }); accounts.into_iter().chain(remaining).collect::>() @@ -309,8 +298,8 @@ fn anchor_test_deliver() -> Result<()> { }) .args(instruction::MockDeliver { port_id: port_id.clone(), - _channel_id: channel_id.clone(), - _base_denom: BASE_DENOM.to_string(), + channel_id: channel_id.clone(), + base_denom: BASE_DENOM.to_string(), commitment_prefix, client_id, counterparty_client_id: counter_party_client_id, @@ -392,13 +381,16 @@ fn anchor_test_deliver() -> Result<()> { serialized_data ) .unwrap(), - proof_height_on_a: Height::new(0, 1).unwrap(), + proof_height_on_a: solana_ibc_storage_account.height, signer: ibc::Signer::from(authority.pubkey().to_string()) }, ibc::core::ics04_channel::msgs::PacketMsg::Recv, ibc::core::MsgEnvelope::Packet, ); + println!("This is trie {:?}", trie); + println!("This is storage {:?}", storage); + /* The remaining accounts consists of the following accounts - sender token account @@ -445,7 +437,6 @@ fn anchor_test_deliver() -> Result<()> { println!("This is the mint information {:?}", mint_info); - Ok(()) } diff --git a/solana/solana-ibc/programs/solana-ibc/src/validation_context.rs b/solana/solana-ibc/programs/solana-ibc/src/validation_context.rs index a582644f..ccf4f4d7 100644 --- a/solana/solana-ibc/programs/solana-ibc/src/validation_context.rs +++ b/solana/solana-ibc/programs/solana-ibc/src/validation_context.rs @@ -2,6 +2,7 @@ use std::str::FromStr; use std::time::Duration; use anchor_lang::prelude::{borsh, Pubkey}; +use anchor_lang::solana_program::msg; use ibc::core::ics02_client::error::ClientError; use ibc::core::ics03_connection::connection::ConnectionEnd; use ibc::core::ics03_connection::error::ConnectionError; @@ -285,6 +286,7 @@ impl ibc::core::ics02_client::ClientValidationContext client_id: &ClientId, height: &Height, ) -> Result { + msg!("This is the client id {}", client_id); let store = self.borrow(); store .private From f3bb76be5e58ca003014caa0c4d724d88374335c Mon Sep 17 00:00:00 2001 From: dhruvja Date: Sat, 18 Nov 2023 21:00:14 +0530 Subject: [PATCH 26/57] added chain back to method --- .../solana-ibc/programs/solana-ibc/src/lib.rs | 8 ++++---- .../programs/solana-ibc/src/storage.rs | 1 + .../programs/solana-ibc/src/tests.rs | 18 +++++++++--------- 3 files changed, 14 insertions(+), 13 deletions(-) diff --git a/solana/solana-ibc/programs/solana-ibc/src/lib.rs b/solana/solana-ibc/programs/solana-ibc/src/lib.rs index e9474c65..11481abd 100644 --- a/solana/solana-ibc/programs/solana-ibc/src/lib.rs +++ b/solana/solana-ibc/programs/solana-ibc/src/lib.rs @@ -161,7 +161,7 @@ pub mod solana_ibc { // Before anything else, try generating a new guest block. However, if // that fails it’s not an error condition. We do this at the beginning // of any request. - // ctx.accounts.chain.maybe_generate_block(&provable, Some(host_head))?; + ctx.accounts.chain.maybe_generate_block(&provable, Some(host_head))?; let mut store = storage::IbcStorage::new(storage::IbcStorageInner { private, @@ -189,7 +189,7 @@ pub mod solana_ibc { // `store` is the only reference to inner storage making refcount == 1 // which means try_into_inner will succeed. - let inner = store.try_into_inner().unwrap(); + // let inner = store.try_into_inner().unwrap(); // msg!("This is final structure {:?}", inner.private); @@ -450,8 +450,8 @@ pub struct Deliver<'info> { packets: Account<'info, IBCPackets>, // /// The guest blockchain data. - // #[account(init_if_needed, payer = sender, seeds = [CHAIN_SEED], bump, space = 10000)] - // chain: Box>, + #[account(init_if_needed, payer = sender, seeds = [CHAIN_SEED], bump, space = 10000)] + chain: Box>, system_program: Program<'info, System>, } diff --git a/solana/solana-ibc/programs/solana-ibc/src/storage.rs b/solana/solana-ibc/programs/solana-ibc/src/storage.rs index 0c08641d..f03e32a0 100644 --- a/solana/solana-ibc/programs/solana-ibc/src/storage.rs +++ b/solana/solana-ibc/programs/solana-ibc/src/storage.rs @@ -184,6 +184,7 @@ impl<'a, 'b, 'c> IbcStorage<'a, 'b, 'c> { /// /// This is mostly a wrapper around [`Rc::try_unwrap`]. Returns `None` if /// there are other references to the inner storage object. + #[allow(dead_code)] pub fn try_into_inner(self) -> Option> { Rc::try_unwrap(self.0).ok().map(RefCell::into_inner) } diff --git a/solana/solana-ibc/programs/solana-ibc/src/tests.rs b/solana/solana-ibc/programs/solana-ibc/src/tests.rs index 1119a9d5..ddf36f41 100644 --- a/solana/solana-ibc/programs/solana-ibc/src/tests.rs +++ b/solana/solana-ibc/programs/solana-ibc/src/tests.rs @@ -75,7 +75,7 @@ pub struct DeliverWithRemainingAccounts { storage: Pubkey, trie: Pubkey, packets: Pubkey, - // chain: Pubkey, + chain: Pubkey, system_program: Pubkey, remaining_accounts: Vec, } @@ -106,11 +106,11 @@ impl ToAccountMetas for DeliverWithRemainingAccounts { is_signer: false, is_writable: true, }, - // AccountMeta { - // pubkey: self.chain, - // is_signer: false, - // is_writable: true, - // }, + AccountMeta { + pubkey: self.chain, + is_signer: false, + is_writable: true, + }, AccountMeta { pubkey: self.system_program, is_signer: false, @@ -182,7 +182,7 @@ fn anchor_test_deliver() -> Result<()> { storage, trie, packets, - // chain, + chain, system_program: system_program::ID, }) .args(instruction::Deliver { message }) @@ -238,7 +238,7 @@ fn anchor_test_deliver() -> Result<()> { storage, trie, packets, - // chain: chain.clone(), + chain: chain.clone(), system_program: system_program::ID, }) .args(instruction::Deliver { message }) @@ -420,7 +420,7 @@ fn anchor_test_deliver() -> Result<()> { trie, system_program: system_program::ID, packets, - // chain, + chain, remaining_accounts, }) .args(instruction::Deliver { message }) From 52f10a8f4e4ca09b4129044568de7ff6597c8ecd Mon Sep 17 00:00:00 2001 From: dhruvja Date: Sat, 18 Nov 2023 21:00:39 +0530 Subject: [PATCH 27/57] fmt --- solana/solana-ibc/programs/solana-ibc/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/solana/solana-ibc/programs/solana-ibc/src/lib.rs b/solana/solana-ibc/programs/solana-ibc/src/lib.rs index 11481abd..22d0f0ad 100644 --- a/solana/solana-ibc/programs/solana-ibc/src/lib.rs +++ b/solana/solana-ibc/programs/solana-ibc/src/lib.rs @@ -33,9 +33,9 @@ use ibc::core::ics24_host::path::{ ChannelEndPath, ConnectionPath, SeqRecvPath, SeqSendPath, }; use ibc::core::router::{Module, ModuleId, Router}; -use ibc::core::MsgEnvelope; #[cfg(feature = "mocks")] use ibc::core::ExecutionContext; +use ibc::core::MsgEnvelope; #[cfg(feature = "mocks")] use ibc::{ core::{ics02_client::ClientExecutionContext, ValidationContext}, From 6474db72e0c7c4ddaf02384cbe51eabc81b8e87b Mon Sep 17 00:00:00 2001 From: dhruvja Date: Sun, 19 Nov 2023 00:05:05 +0530 Subject: [PATCH 28/57] fix clippy --- solana/solana-ibc/programs/solana-ibc/src/lib.rs | 4 ++-- .../programs/solana-ibc/src/transfer/impls.rs | 15 +++++++++------ 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/solana/solana-ibc/programs/solana-ibc/src/lib.rs b/solana/solana-ibc/programs/solana-ibc/src/lib.rs index 065fc8c4..d80ada53 100644 --- a/solana/solana-ibc/programs/solana-ibc/src/lib.rs +++ b/solana/solana-ibc/programs/solana-ibc/src/lib.rs @@ -484,9 +484,9 @@ pub struct MockDeliver<'info> { #[account(init_if_needed, payer = sender, seeds = [MINT_ESCROW_SEED], bump, space = 100)] /// CHECK: mint_authority: UncheckedAccount<'info>, - #[account(init_if_needed, payer = sender, seeds = [base_denom.as_bytes().as_ref()], bump, mint::decimals = 6, mint::authority = mint_authority)] + #[account(init_if_needed, payer = sender, seeds = [base_denom.as_bytes()], bump, mint::decimals = 6, mint::authority = mint_authority)] token_mint: Box>, - #[account(init_if_needed, payer = sender, seeds = [port_id.as_bytes().as_ref(), channel_id.as_bytes().as_ref()], bump, token::mint = token_mint, token::authority = sender)] + #[account(init_if_needed, payer = sender, seeds = [port_id.as_bytes(), channel_id.as_bytes()], bump, token::mint = token_mint, token::authority = sender)] escrow_account: Box>, #[account(init_if_needed, payer = sender, associated_token::mint = token_mint, associated_token::authority = sender)] sender_token_account: Box>, diff --git a/solana/solana-ibc/programs/solana-ibc/src/transfer/impls.rs b/solana/solana-ibc/programs/solana-ibc/src/transfer/impls.rs index 5838d0d9..e48f87e2 100644 --- a/solana/solana-ibc/programs/solana-ibc/src/transfer/impls.rs +++ b/solana/solana-ibc/programs/solana-ibc/src/transfer/impls.rs @@ -22,7 +22,7 @@ impl TryFrom for AccountId { type Error = ::Err; fn try_from(value: ibc::Signer) -> Result { - Ok(Pubkey::from_str(&value.as_ref()).map(Self)?) + Pubkey::from_str(value.as_ref()).map(Self) } } @@ -99,7 +99,8 @@ impl TokenTransferExecutionContext for IbcStorage<'_, '_, '_> { outer.as_slice(), //signer PDA ); - Ok(anchor_spl::token::transfer(cpi_ctx, amount_in_u64).unwrap()) + anchor_spl::token::transfer(cpi_ctx, amount_in_u64).unwrap(); + Ok(()) } fn mint_coins_execute( @@ -133,7 +134,7 @@ impl TokenTransferExecutionContext for IbcStorage<'_, '_, '_> { get_account_info_from_key(accounts, mint_authority_key)?; let bump_vector = mint_authority_bump.to_le_bytes(); - let inner = vec![MINT_ESCROW_SEED.as_ref(), bump_vector.as_ref()]; + let inner = vec![MINT_ESCROW_SEED, bump_vector.as_ref()]; let outer = vec![inner.as_slice()]; // Below is the actual instruction that we are going to send to the Token program. @@ -148,7 +149,8 @@ impl TokenTransferExecutionContext for IbcStorage<'_, '_, '_> { outer.as_slice(), //signer PDA ); - Ok(anchor_spl::token::mint_to(cpi_ctx, amount_in_u64).unwrap()) + anchor_spl::token::mint_to(cpi_ctx, amount_in_u64).unwrap(); + Ok(()) } fn burn_coins_execute( @@ -194,7 +196,8 @@ impl TokenTransferExecutionContext for IbcStorage<'_, '_, '_> { outer.as_slice(), //signer PDA ); - Ok(anchor_spl::token::burn(cpi_ctx, amount_in_u64).unwrap()) + anchor_spl::token::burn(cpi_ctx, amount_in_u64).unwrap(); + Ok(()) } } @@ -211,7 +214,7 @@ impl TokenTransferValidationContext for IbcStorage<'_, '_, '_> { channel_id: &ChannelId, ) -> Result { let seeds = - [port_id.as_bytes().as_ref(), channel_id.as_bytes().as_ref()]; + [port_id.as_bytes(), channel_id.as_bytes()]; let (escrow_account_key, _bump) = Pubkey::find_program_address(&seeds, &crate::ID); Ok(AccountId(escrow_account_key)) From 4e08b5ac902b65d4b133ecc5f7817eb118f01622 Mon Sep 17 00:00:00 2001 From: dhruvja Date: Sun, 19 Nov 2023 00:06:02 +0530 Subject: [PATCH 29/57] fmt --- solana/solana-ibc/programs/solana-ibc/src/transfer/impls.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/solana/solana-ibc/programs/solana-ibc/src/transfer/impls.rs b/solana/solana-ibc/programs/solana-ibc/src/transfer/impls.rs index e48f87e2..dfa8b26a 100644 --- a/solana/solana-ibc/programs/solana-ibc/src/transfer/impls.rs +++ b/solana/solana-ibc/programs/solana-ibc/src/transfer/impls.rs @@ -213,8 +213,7 @@ impl TokenTransferValidationContext for IbcStorage<'_, '_, '_> { port_id: &PortId, channel_id: &ChannelId, ) -> Result { - let seeds = - [port_id.as_bytes(), channel_id.as_bytes()]; + let seeds = [port_id.as_bytes(), channel_id.as_bytes()]; let (escrow_account_key, _bump) = Pubkey::find_program_address(&seeds, &crate::ID); Ok(AccountId(escrow_account_key)) From 3a5ae71ce3621a1f875e6a729d6e9f6433904b60 Mon Sep 17 00:00:00 2001 From: Michal Nazarewicz Date: Sun, 19 Nov 2023 19:14:13 +0100 Subject: [PATCH 30/57] reduce diff noise --- solana/solana-ibc/programs/solana-ibc/src/error.rs | 14 -------------- .../programs/solana-ibc/src/execution_context.rs | 9 ++++----- solana/solana-ibc/programs/solana-ibc/src/lib.rs | 2 -- .../solana-ibc/programs/solana-ibc/src/storage.rs | 12 ++++++------ 4 files changed, 10 insertions(+), 27 deletions(-) diff --git a/solana/solana-ibc/programs/solana-ibc/src/error.rs b/solana/solana-ibc/programs/solana-ibc/src/error.rs index 07232a62..c62d4231 100644 --- a/solana/solana-ibc/programs/solana-ibc/src/error.rs +++ b/solana/solana-ibc/programs/solana-ibc/src/error.rs @@ -117,20 +117,6 @@ impl From for Error { } } -impl From for Error { - #[inline] - fn from(err: ibc::core::ContextError) -> Self { - Self::RouterError(err.into()) - } -} - -impl From for Error { - #[inline] - fn from(err: ibc::core::ics02_client::error::ClientError) -> Self { - ibc::core::ContextError::from(err).into() - } -} - impl From for anchor_lang::error::AnchorError { fn from(err: Error) -> Self { Self { diff --git a/solana/solana-ibc/programs/solana-ibc/src/execution_context.rs b/solana/solana-ibc/programs/solana-ibc/src/execution_context.rs index cd8ce37c..ef13a91a 100644 --- a/solana/solana-ibc/programs/solana-ibc/src/execution_context.rs +++ b/solana/solana-ibc/programs/solana-ibc/src/execution_context.rs @@ -112,8 +112,7 @@ impl ClientExecutionContext for IbcStorage<'_, '_, '_> { timestamp: Timestamp, ) -> Result<(), ContextError> { // msg!("store_update_time({}, {}, {})", client_id, height, timestamp); - let mut store = self.borrow_mut(); - store + self.borrow_mut() .private .client_mut(&client_id, false)? .processed_times @@ -128,8 +127,7 @@ impl ClientExecutionContext for IbcStorage<'_, '_, '_> { host_height: Height, ) -> Result<(), ContextError> { // msg!("store_update_height({}, {}, {})", client_id, height, host_height); - let mut store = self.borrow_mut(); - store + self.borrow_mut() .private .client_mut(&client_id, false)? .processed_heights @@ -139,7 +137,8 @@ impl ClientExecutionContext for IbcStorage<'_, '_, '_> { } impl ExecutionContext for IbcStorage<'_, '_, '_> { - /// The clients are stored in the vector so we can easily find how many clients were created. So thats why this method doesnt do anything. + /// The clients are stored in the vector so we can easily find how many + /// clients were created. So thats why this method doesnt do anything. fn increase_client_counter(&mut self) -> Result { Ok(()) } fn store_connection( diff --git a/solana/solana-ibc/programs/solana-ibc/src/lib.rs b/solana/solana-ibc/programs/solana-ibc/src/lib.rs index 9f774d52..b9e19463 100644 --- a/solana/solana-ibc/programs/solana-ibc/src/lib.rs +++ b/solana/solana-ibc/programs/solana-ibc/src/lib.rs @@ -68,8 +68,6 @@ mod validation_context; #[anchor_lang::program] pub mod solana_ibc { - - use super::*; /// Initialises the guest blockchain with given configuration and genesis diff --git a/solana/solana-ibc/programs/solana-ibc/src/storage.rs b/solana/solana-ibc/programs/solana-ibc/src/storage.rs index ff6d8e98..76cf4d32 100644 --- a/solana/solana-ibc/programs/solana-ibc/src/storage.rs +++ b/solana/solana-ibc/programs/solana-ibc/src/storage.rs @@ -314,9 +314,9 @@ impl<'a, 'b, 'c> IbcStorage<'a, 'b, 'c> { /// # Panics /// /// Panics if the value is currently mutably borrowed. - pub fn borrow<'d>( - &'d self, - ) -> core::cell::Ref<'d, IbcStorageInner<'a, 'b, 'c>> { + pub fn borrow<'s>( + &'s self, + ) -> core::cell::Ref<'s, IbcStorageInner<'a, 'b, 'c>> { self.0.borrow() } @@ -325,9 +325,9 @@ impl<'a, 'b, 'c> IbcStorage<'a, 'b, 'c> { /// # Panics /// /// Panics if the value is currently borrowed. - pub fn borrow_mut<'d>( - &'d self, - ) -> core::cell::RefMut<'d, IbcStorageInner<'a, 'b, 'c>> { + pub fn borrow_mut<'s>( + &'s self, + ) -> core::cell::RefMut<'s, IbcStorageInner<'a, 'b, 'c>> { self.0.borrow_mut() } } From 89a67cc4ef3f1f01f5e77729fb0184113afe9e16 Mon Sep 17 00:00:00 2001 From: Michal Nazarewicz Date: Sun, 19 Nov 2023 19:29:25 +0100 Subject: [PATCH 31/57] Revert "reduce diff noise" This reverts commit 3a5ae71ce3621a1f875e6a729d6e9f6433904b60. --- solana/solana-ibc/programs/solana-ibc/src/error.rs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/solana/solana-ibc/programs/solana-ibc/src/error.rs b/solana/solana-ibc/programs/solana-ibc/src/error.rs index c62d4231..07232a62 100644 --- a/solana/solana-ibc/programs/solana-ibc/src/error.rs +++ b/solana/solana-ibc/programs/solana-ibc/src/error.rs @@ -117,6 +117,20 @@ impl From for Error { } } +impl From for Error { + #[inline] + fn from(err: ibc::core::ContextError) -> Self { + Self::RouterError(err.into()) + } +} + +impl From for Error { + #[inline] + fn from(err: ibc::core::ics02_client::error::ClientError) -> Self { + ibc::core::ContextError::from(err).into() + } +} + impl From for anchor_lang::error::AnchorError { fn from(err: Error) -> Self { Self { From a5ca4352a34af275a47dcb1b9712a8b6f0e0c1f0 Mon Sep 17 00:00:00 2001 From: dhruvja Date: Mon, 20 Nov 2023 19:51:50 +0530 Subject: [PATCH 32/57] added mock deliver in a seperate file --- .../programs/solana-ibc/src/error.rs | 14 ++ .../solana-ibc/programs/solana-ibc/src/lib.rs | 205 +----------------- .../programs/solana-ibc/src/mocks.rs | 199 +++++++++++++++++ .../programs/solana-ibc/src/tests.rs | 9 +- .../programs/solana-ibc/src/transfer/impls.rs | 3 +- 5 files changed, 234 insertions(+), 196 deletions(-) create mode 100644 solana/solana-ibc/programs/solana-ibc/src/mocks.rs diff --git a/solana/solana-ibc/programs/solana-ibc/src/error.rs b/solana/solana-ibc/programs/solana-ibc/src/error.rs index c62d4231..07232a62 100644 --- a/solana/solana-ibc/programs/solana-ibc/src/error.rs +++ b/solana/solana-ibc/programs/solana-ibc/src/error.rs @@ -117,6 +117,20 @@ impl From for Error { } } +impl From for Error { + #[inline] + fn from(err: ibc::core::ContextError) -> Self { + Self::RouterError(err.into()) + } +} + +impl From for Error { + #[inline] + fn from(err: ibc::core::ics02_client::error::ClientError) -> Self { + ibc::core::ContextError::from(err).into() + } +} + impl From for anchor_lang::error::AnchorError { fn from(err: Error) -> Self { Self { diff --git a/solana/solana-ibc/programs/solana-ibc/src/lib.rs b/solana/solana-ibc/programs/solana-ibc/src/lib.rs index b9e19463..008023a6 100644 --- a/solana/solana-ibc/programs/solana-ibc/src/lib.rs +++ b/solana/solana-ibc/programs/solana-ibc/src/lib.rs @@ -8,39 +8,14 @@ extern crate alloc; use anchor_lang::prelude::*; use anchor_lang::solana_program; use anchor_spl::associated_token::AssociatedToken; -#[cfg(feature = "mocks")] -use anchor_spl::token::MintTo; use anchor_spl::token::{Mint, Token, TokenAccount}; use borsh::BorshDeserialize; -#[cfg(feature = "mocks")] -use ibc::core::ics03_connection::connection::{ - ConnectionEnd, Counterparty, State as ConnState, -}; -#[cfg(feature = "mocks")] -use ibc::core::ics03_connection::version::Version; -#[cfg(feature = "mocks")] -use ibc::core::ics04_channel::channel::{ - ChannelEnd, Counterparty as ChanCounterparty, Order, State as ChannelState, -}; -#[cfg(feature = "mocks")] -use ibc::core::ics04_channel::Version as ChanVersion; use ibc::core::ics23_commitment::commitment::CommitmentPrefix; -#[cfg(feature = "mocks")] -use ibc::core::ics24_host::identifier::ConnectionId; use ibc::core::ics24_host::identifier::{ChannelId, ClientId, PortId}; -#[cfg(feature = "mocks")] -use ibc::core::ics24_host::path::{ - ChannelEndPath, ConnectionPath, SeqRecvPath, SeqSendPath, -}; use ibc::core::router::{Module, ModuleId, Router}; -#[cfg(feature = "mocks")] -use ibc::core::ExecutionContext; use ibc::core::MsgEnvelope; #[cfg(feature = "mocks")] -use ibc::{ - core::{ics02_client::ClientExecutionContext, ValidationContext}, - mock::client_state::MockClientState, -}; +use mocks::mock_deliver_impl; use storage::IbcPackets; const CHAIN_SEED: &[u8] = b"chain"; @@ -59,12 +34,13 @@ mod error; mod events; mod execution_context; mod host; +#[cfg(feature = "mocks")] +mod mocks; mod storage; #[cfg(test)] mod tests; mod transfer; mod validation_context; -// mod client_context; #[anchor_lang::program] pub mod solana_ibc { @@ -204,177 +180,20 @@ pub mod solana_ibc { ) -> Result<()> { #[cfg(feature = "mocks")] { - let private: &mut storage::PrivateStorage = - &mut ctx.accounts.storage; - // msg!("This is private: {private:?}"); - let provable = - storage::get_provable_from(&ctx.accounts.trie, "trie")?; - let packets: &mut IbcPackets = &mut ctx.accounts.packets; - let accounts = ctx.remaining_accounts; - - let host_head = host::Head::get()?; - let (host_timestamp, host_height) = host_head - .ibc_timestamp() - .and_then(|ts| host_head.ibc_height().map(|h| (ts, h))) - .map_err(error::Error::from) - .map_err(|err| error!((&err)))?; - - let mut store = - storage::IbcStorage::new(storage::IbcStorageInner { - private, - provable, - packets, - accounts: accounts.to_vec(), - host_head, - }); - - let any_client_state = store.client_state(&client_id).unwrap(); - let client_state: MockClientState = match any_client_state { - client_state::AnyClientState::Tendermint(_) => { - panic!("Only for mocks") - } - client_state::AnyClientState::Mock(mock) => mock, - }; - - - // Store update time since its not called during mocks - store - .store_update_time( - client_id.clone(), - client_state.latest_height(), - host_timestamp, - ) - .unwrap(); - store - .store_update_height( - client_id.clone(), - client_state.latest_height(), - host_height, - ) - .unwrap(); - - let connection_id_on_a = ConnectionId::new(0); - let connection_id_on_b = ConnectionId::new(1); - let delay_period = core::time::Duration::from_nanos(0); - let connection_counterparty = Counterparty::new( - counterparty_client_id.clone(), - Some(connection_id_on_b.clone()), + mock_deliver_impl( + ctx, + port_id, + channel_id, + base_denom, commitment_prefix, - ); - let connection_end_on_a = ConnectionEnd::new( - ConnState::Open, - client_id.clone(), - connection_counterparty.clone(), - vec![Version::default()], - delay_period, - ) - .unwrap(); - let connection_end_on_b = ConnectionEnd::new( - ConnState::Open, client_id, - connection_counterparty, - vec![Version::default()], - delay_period, + counterparty_client_id, ) .unwrap(); - - let counterparty = - ChanCounterparty::new(port_id.clone(), Some(ChannelId::new(0))); - let channel_end_on_a = ChannelEnd::new( - ChannelState::Open, - Order::Unordered, - counterparty.clone(), - vec![connection_id_on_a.clone()], - ChanVersion::new( - ibc::applications::transfer::VERSION.to_string(), - ), - ) - .unwrap(); - let channel_end_on_b = ChannelEnd::new( - ChannelState::Open, - Order::Unordered, - counterparty, - vec![connection_id_on_b.clone()], - ChanVersion::new( - ibc::applications::transfer::VERSION.to_string(), - ), - ) - .unwrap(); - let channel_id_on_a = ChannelId::new(0); - let channel_id_on_b = ChannelId::new(1); - - // For Client on Chain A - store - .store_connection( - &ConnectionPath(connection_id_on_a), - connection_end_on_a, - ) - .unwrap(); - store - .store_channel( - &ChannelEndPath(port_id.clone(), channel_id_on_a.clone()), - channel_end_on_a, - ) - .unwrap(); - store - .store_next_sequence_send( - &SeqSendPath(port_id.clone(), channel_id_on_a.clone()), - 1.into(), - ) - .unwrap(); - store - .store_next_sequence_recv( - &SeqRecvPath(port_id.clone(), channel_id_on_a), - 1.into(), - ) - .unwrap(); - - // For Client on chain b - store - .store_connection( - &ConnectionPath(connection_id_on_b), - connection_end_on_b, - ) - .unwrap(); - store - .store_channel( - &ChannelEndPath(port_id.clone(), channel_id_on_b.clone()), - channel_end_on_b, - ) - .unwrap(); - store - .store_next_sequence_send( - &SeqSendPath(port_id.clone(), channel_id_on_b.clone()), - 1.into(), - ) - .unwrap(); - store - .store_next_sequence_recv( - &SeqRecvPath(port_id, channel_id_on_b), - 1.into(), - ) - .unwrap(); - - // Minting some tokens to the authority so that he can do the transfer - let bump_vector = - ctx.bumps.get("mint_authority").unwrap().to_le_bytes(); - let inner = vec![MINT_ESCROW_SEED, bump_vector.as_ref()]; - let outer = vec![inner.as_slice()]; - - // Mint some tokens to escrow account - let mint_instruction = MintTo { - mint: ctx.accounts.token_mint.to_account_info(), - to: ctx.accounts.sender_token_account.to_account_info(), - authority: ctx.accounts.mint_authority.to_account_info(), - }; - let cpi_ctx = CpiContext::new_with_signer( - ctx.accounts.token_program.to_account_info(), - mint_instruction, - outer.as_slice(), //signer PDA - ); - anchor_spl::token::mint_to(cpi_ctx, 10000000)?; + Ok(()) } - Ok(()) + #[cfg(not(feature = "mocks"))] + panic!("This method is only for mocks"); } } diff --git a/solana/solana-ibc/programs/solana-ibc/src/mocks.rs b/solana/solana-ibc/programs/solana-ibc/src/mocks.rs new file mode 100644 index 00000000..2dadd1b6 --- /dev/null +++ b/solana/solana-ibc/programs/solana-ibc/src/mocks.rs @@ -0,0 +1,199 @@ +extern crate alloc; + +use anchor_lang::prelude::*; +use anchor_spl::token::MintTo; +use ibc::core::ics02_client::ClientExecutionContext; +use ibc::core::ics03_connection::connection::{ + ConnectionEnd, Counterparty, State as ConnState, +}; +use ibc::core::ics03_connection::version::Version; +use ibc::core::ics04_channel::channel::{ + ChannelEnd, Counterparty as ChanCounterparty, Order, State as ChannelState, +}; +use ibc::core::ics04_channel::Version as ChanVersion; +use ibc::core::ics23_commitment::commitment::CommitmentPrefix; +use ibc::core::ics24_host::identifier::{ + ChannelId, ClientId, ConnectionId, PortId, +}; +use ibc::core::ics24_host::path::{ + ChannelEndPath, ConnectionPath, SeqRecvPath, SeqSendPath, +}; +use ibc::core::{ExecutionContext, ValidationContext}; +use ibc::mock::client_state::MockClientState; +use storage::IbcPackets; + +use crate::{ + client_state, error, host, storage, MockDeliver, MINT_ESCROW_SEED, +}; + +pub fn mock_deliver_impl( + ctx: Context, + port_id: PortId, + _channel_id: ChannelId, + _base_denom: String, + commitment_prefix: CommitmentPrefix, + client_id: ClientId, + counterparty_client_id: ClientId, +) -> Result<()> { + let private: &mut storage::PrivateStorage = &mut ctx.accounts.storage; + // msg!("This is private: {private:?}"); + let provable = storage::get_provable_from(&ctx.accounts.trie, "trie")?; + let packets: &mut IbcPackets = &mut ctx.accounts.packets; + let accounts = ctx.remaining_accounts; + + let host_head = host::Head::get()?; + let (host_timestamp, host_height) = host_head + .ibc_timestamp() + .and_then(|ts| host_head.ibc_height().map(|h| (ts, h))) + .map_err(error::Error::from) + .map_err(|err| error!((&err)))?; + + let mut store = storage::IbcStorage::new(storage::IbcStorageInner { + private, + provable, + packets, + accounts: accounts.to_vec(), + host_head, + }); + + let any_client_state = store.client_state(&client_id).unwrap(); + let client_state: MockClientState = match any_client_state { + client_state::AnyClientState::Tendermint(_) => { + panic!("Only for mocks") + } + client_state::AnyClientState::Mock(mock) => mock, + }; + + // Store update time since its not called during mocks + store + .store_update_time( + client_id.clone(), + client_state.latest_height(), + host_timestamp, + ) + .unwrap(); + store + .store_update_height( + client_id.clone(), + client_state.latest_height(), + host_height, + ) + .unwrap(); + + let connection_id_on_a = ConnectionId::new(0); + let connection_id_on_b = ConnectionId::new(1); + let delay_period = core::time::Duration::from_nanos(0); + let connection_counterparty = Counterparty::new( + counterparty_client_id.clone(), + Some(connection_id_on_b.clone()), + commitment_prefix, + ); + let connection_end_on_a = ConnectionEnd::new( + ConnState::Open, + client_id.clone(), + connection_counterparty.clone(), + vec![Version::default()], + delay_period, + ) + .unwrap(); + let connection_end_on_b = ConnectionEnd::new( + ConnState::Open, + client_id, + connection_counterparty, + vec![Version::default()], + delay_period, + ) + .unwrap(); + + let counterparty = + ChanCounterparty::new(port_id.clone(), Some(ChannelId::new(0))); + let channel_end_on_a = ChannelEnd::new( + ChannelState::Open, + Order::Unordered, + counterparty.clone(), + vec![connection_id_on_a.clone()], + ChanVersion::new(ibc::applications::transfer::VERSION.to_string()), + ) + .unwrap(); + let channel_end_on_b = ChannelEnd::new( + ChannelState::Open, + Order::Unordered, + counterparty, + vec![connection_id_on_b.clone()], + ChanVersion::new(ibc::applications::transfer::VERSION.to_string()), + ) + .unwrap(); + let channel_id_on_a = ChannelId::new(0); + let channel_id_on_b = ChannelId::new(1); + + // For Client on Chain A + store + .store_connection( + &ConnectionPath(connection_id_on_a), + connection_end_on_a, + ) + .unwrap(); + store + .store_channel( + &ChannelEndPath(port_id.clone(), channel_id_on_a.clone()), + channel_end_on_a, + ) + .unwrap(); + store + .store_next_sequence_send( + &SeqSendPath(port_id.clone(), channel_id_on_a.clone()), + 1.into(), + ) + .unwrap(); + store + .store_next_sequence_recv( + &SeqRecvPath(port_id.clone(), channel_id_on_a), + 1.into(), + ) + .unwrap(); + + // For Client on chain b + store + .store_connection( + &ConnectionPath(connection_id_on_b), + connection_end_on_b, + ) + .unwrap(); + store + .store_channel( + &ChannelEndPath(port_id.clone(), channel_id_on_b.clone()), + channel_end_on_b, + ) + .unwrap(); + store + .store_next_sequence_send( + &SeqSendPath(port_id.clone(), channel_id_on_b.clone()), + 1.into(), + ) + .unwrap(); + store + .store_next_sequence_recv( + &SeqRecvPath(port_id, channel_id_on_b), + 1.into(), + ) + .unwrap(); + + // Minting some tokens to the authority so that he can do the transfer + let bump_vector = ctx.bumps.get("mint_authority").unwrap().to_le_bytes(); + let inner = vec![MINT_ESCROW_SEED, bump_vector.as_ref()]; + let outer = vec![inner.as_slice()]; + + // Mint some tokens to escrow account + let mint_instruction = MintTo { + mint: ctx.accounts.token_mint.to_account_info(), + to: ctx.accounts.sender_token_account.to_account_info(), + authority: ctx.accounts.mint_authority.to_account_info(), + }; + let cpi_ctx = CpiContext::new_with_signer( + ctx.accounts.token_program.to_account_info(), + mint_instruction, + outer.as_slice(), //signer PDA + ); + anchor_spl::token::mint_to(cpi_ctx, 10000000)?; + Ok(()) +} diff --git a/solana/solana-ibc/programs/solana-ibc/src/tests.rs b/solana/solana-ibc/programs/solana-ibc/src/tests.rs index 646d374b..3946e61f 100644 --- a/solana/solana-ibc/programs/solana-ibc/src/tests.rs +++ b/solana/solana-ibc/programs/solana-ibc/src/tests.rs @@ -7,6 +7,7 @@ use anchor_client::anchor_lang::system_program; use anchor_client::solana_client::rpc_client::RpcClient; use anchor_client::solana_client::rpc_config::RpcSendTransactionConfig; use anchor_client::solana_sdk::commitment_config::CommitmentConfig; +use anchor_client::solana_sdk::compute_budget::ComputeBudgetInstruction; use anchor_client::solana_sdk::pubkey::Pubkey; use anchor_client::solana_sdk::signature::{Keypair, Signature, Signer}; use anchor_client::{Client, Cluster}; @@ -130,7 +131,7 @@ impl ToAccountMetas for DeliverWithRemainingAccounts { fn anchor_test_deliver() -> Result<()> { let authority = Rc::new(Keypair::new()); println!("This is pubkey {}", authority.pubkey().to_string()); - let lamports = 10_000_000_000; + let lamports = 2_000_000_000; let client = Client::new_with_options( Cluster::Localnet, @@ -279,6 +280,9 @@ fn anchor_test_deliver() -> Result<()> { let sig = program .request() + .instruction(ComputeBudgetInstruction::set_compute_unit_limit( + 1_000_000u32, + )) .accounts(accounts::MockDeliver { sender: authority.pubkey(), sender_token_account: sender_token_address, @@ -392,6 +396,9 @@ fn anchor_test_deliver() -> Result<()> { let sig = program .request() + .instruction(ComputeBudgetInstruction::set_compute_unit_limit( + 1_000_000u32, + )) .accounts(DeliverWithRemainingAccounts { sender: authority.pubkey(), storage, diff --git a/solana/solana-ibc/programs/solana-ibc/src/transfer/impls.rs b/solana/solana-ibc/programs/solana-ibc/src/transfer/impls.rs index dfa8b26a..2cbbb756 100644 --- a/solana/solana-ibc/programs/solana-ibc/src/transfer/impls.rs +++ b/solana/solana-ibc/programs/solana-ibc/src/transfer/impls.rs @@ -109,12 +109,11 @@ impl TokenTransferExecutionContext for IbcStorage<'_, '_, '_> { amt: &PrefixedCoin, ) -> Result<(), TokenTransferError> { msg!( - "Minting coins for account {:?}, trace path {}, base denom {}", + "Minting coins for account {}, trace path {}, base denom {}", account, amt.denom.trace_path, amt.denom.base_denom ); - msg!("This should appear before"); let receiver_id = Pubkey::from(account); let base_denom = amt.denom.base_denom.to_string(); let amount = amt.amount; From 82d44bfba56e05c64bfba245a418171ac789115e Mon Sep 17 00:00:00 2001 From: dhruvja Date: Tue, 21 Nov 2023 20:24:28 +0530 Subject: [PATCH 33/57] fixed transfer and added test for both source and dest transfer --- .../solana-ibc/programs/solana-ibc/src/lib.rs | 14 +- .../programs/solana-ibc/src/mocks.rs | 4 +- .../programs/solana-ibc/src/tests.rs | 210 +++++++++++------- .../programs/solana-ibc/src/transfer/impls.rs | 16 +- 4 files changed, 151 insertions(+), 93 deletions(-) diff --git a/solana/solana-ibc/programs/solana-ibc/src/lib.rs b/solana/solana-ibc/programs/solana-ibc/src/lib.rs index 15f367ec..7f912bc6 100644 --- a/solana/solana-ibc/programs/solana-ibc/src/lib.rs +++ b/solana/solana-ibc/programs/solana-ibc/src/lib.rs @@ -172,7 +172,7 @@ pub mod solana_ibc { pub fn mock_deliver( ctx: Context, port_id: PortId, - channel_id: ChannelId, + channel_id_on_b: ChannelId, base_denom: String, commitment_prefix: CommitmentPrefix, client_id: ClientId, @@ -183,7 +183,7 @@ pub mod solana_ibc { mock_deliver_impl( ctx, port_id, - channel_id, + channel_id_on_b, base_denom, commitment_prefix, client_id, @@ -268,7 +268,7 @@ pub struct Deliver<'info> { } #[derive(Accounts)] -#[instruction(port_id: PortId, channel_id: ChannelId, base_denom: String)] +#[instruction(port_id: PortId, channel_id_on_b: ChannelId, base_denom: String)] pub struct MockDeliver<'info> { #[account(mut)] sender: Signer<'info>, @@ -277,18 +277,18 @@ pub struct MockDeliver<'info> { receiver: AccountInfo<'info>, /// The account holding private IBC storage. - #[account(mut, seeds = [SOLANA_IBC_STORAGE_SEED],bump, realloc = 10000, realloc::payer = sender, realloc::zero = false)] + #[account(mut, seeds = [SOLANA_IBC_STORAGE_SEED],bump, realloc = 10240, realloc::payer = sender, realloc::zero = false)] storage: Box>, /// The account holding provable IBC storage, i.e. the trie. /// /// CHECK: Account’s owner is checked by [`storage::get_provable_from`] /// function. - #[account(init_if_needed, payer = sender, seeds = [TRIE_SEED], bump, space = 10000)] + #[account(init_if_needed, payer = sender, seeds = [TRIE_SEED], bump, space = 10240)] trie: UncheckedAccount<'info>, /// The account holding packets. - #[account(init_if_needed, payer = sender, seeds = [PACKET_SEED], bump, space = 1000)] + #[account(init_if_needed, payer = sender, seeds = [PACKET_SEED], bump, space = 10240)] packets: Box>, /// The below accounts are being created for testing purposes only. @@ -299,7 +299,7 @@ pub struct MockDeliver<'info> { mint_authority: UncheckedAccount<'info>, #[account(init_if_needed, payer = sender, seeds = [base_denom.as_bytes()], bump, mint::decimals = 6, mint::authority = mint_authority)] token_mint: Box>, - #[account(init_if_needed, payer = sender, seeds = [port_id.as_bytes(), channel_id.as_bytes()], bump, token::mint = token_mint, token::authority = sender)] + #[account(init_if_needed, payer = sender, seeds = [port_id.as_bytes(), channel_id_on_b.as_bytes()], bump, token::mint = token_mint, token::authority = mint_authority)] escrow_account: Box>, #[account(init_if_needed, payer = sender, associated_token::mint = token_mint, associated_token::authority = sender)] sender_token_account: Box>, diff --git a/solana/solana-ibc/programs/solana-ibc/src/mocks.rs b/solana/solana-ibc/programs/solana-ibc/src/mocks.rs index 2dadd1b6..9ba0f460 100644 --- a/solana/solana-ibc/programs/solana-ibc/src/mocks.rs +++ b/solana/solana-ibc/programs/solana-ibc/src/mocks.rs @@ -178,7 +178,7 @@ pub fn mock_deliver_impl( ) .unwrap(); - // Minting some tokens to the authority so that he can do the transfer + // Minting some tokens to the escrow so that he can do the transfer let bump_vector = ctx.bumps.get("mint_authority").unwrap().to_le_bytes(); let inner = vec![MINT_ESCROW_SEED, bump_vector.as_ref()]; let outer = vec![inner.as_slice()]; @@ -186,7 +186,7 @@ pub fn mock_deliver_impl( // Mint some tokens to escrow account let mint_instruction = MintTo { mint: ctx.accounts.token_mint.to_account_info(), - to: ctx.accounts.sender_token_account.to_account_info(), + to: ctx.accounts.escrow_account.to_account_info(), authority: ctx.accounts.mint_authority.to_account_info(), }; let cpi_ctx = CpiContext::new_with_signer( diff --git a/solana/solana-ibc/programs/solana-ibc/src/tests.rs b/solana/solana-ibc/programs/solana-ibc/src/tests.rs index 3946e61f..e463e6ba 100644 --- a/solana/solana-ibc/programs/solana-ibc/src/tests.rs +++ b/solana/solana-ibc/programs/solana-ibc/src/tests.rs @@ -39,9 +39,10 @@ use crate::storage::PrivateStorage; use crate::{accounts, instruction, MINT_ESCROW_SEED}; const IBC_TRIE_PREFIX: &[u8] = b"ibc/"; -const DENOM: &str = "transfer/channel-1/PICA"; const BASE_DENOM: &str = "PICA"; +const TRANSFER_AMOUNT: u64 = 1000000; + fn airdrop(client: &RpcClient, account: Pubkey, lamports: u64) -> Signature { let balance_before = client.get_balance(&account).unwrap(); println!("This is balance before {}", balance_before); @@ -117,7 +118,6 @@ impl ToAccountMetas for DeliverWithRemainingAccounts { }, ]; - let remaining = self.remaining_accounts.iter().map(|&account| { AccountMeta { pubkey: account, is_signer: false, is_writable: true } }); @@ -261,11 +261,13 @@ fn anchor_test_deliver() -> Result<()> { */ let port_id = PortId::transfer(); - let channel_id = ChannelId::new(0); + let channel_id_on_a = ChannelId::new(0); + let channel_id_on_b = ChannelId::new(1); let receiver = Keypair::new(); - let seeds = [port_id.as_bytes().as_ref(), channel_id.as_bytes().as_ref()]; + let seeds = + [port_id.as_bytes().as_ref(), channel_id_on_b.as_bytes().as_ref()]; let (escrow_account_key, _bump) = Pubkey::find_program_address(&seeds, &crate::ID); let (token_mint_key, _bump) = @@ -277,7 +279,6 @@ fn anchor_test_deliver() -> Result<()> { let receiver_token_address = get_associated_token_address(&receiver.pubkey(), &token_mint_key); - let sig = program .request() .instruction(ComputeBudgetInstruction::set_compute_unit_limit( @@ -300,7 +301,7 @@ fn anchor_test_deliver() -> Result<()> { }) .args(instruction::MockDeliver { port_id: port_id.clone(), - channel_id: channel_id.clone(), + channel_id_on_b: channel_id_on_b.clone(), base_denom: BASE_DENOM.to_string(), commitment_prefix, client_id: client_id.clone(), @@ -329,40 +330,30 @@ fn anchor_test_deliver() -> Result<()> { // Make sure all the accounts needed for transfer are ready ( mint, escrow etc.) // Pass the instruction for transfer - let base_denom: BaseDenom = BaseDenom::from_str(DENOM).unwrap(); - let token: BaseCoin = - Coin { denom: base_denom, amount: Amount::from(1000000) }; - - let packet_data = PacketData { - token: token.into(), - sender: ibc::Signer::from(sender_token_address.to_string()), // Should be a token account - receiver: ibc::Signer::from(receiver_token_address.to_string()), // Should be a token account - memo: String::from("My first tx").into(), - }; - - let serialized_data = serde_json::to_vec(&packet_data).unwrap(); - - let packet = Packet { - seq_on_a: 1.into(), - port_id_on_a: port_id.clone(), - chan_id_on_a: channel_id, - port_id_on_b: port_id, - chan_id_on_b: ChannelId::new(1), - data: serialized_data.clone(), - timeout_height_on_b: TimeoutHeight::Never, - timeout_timestamp_on_b: Timestamp::none(), - }; + /* + * + * On Source chain + * + */ + let packet = construct_packet_from_denom( + port_id.clone(), + channel_id_on_a.clone(), + channel_id_on_a.clone(), + channel_id_on_b.clone(), + 1, + sender_token_address, + receiver_token_address, + String::from("Tx from Source chain"), + ); let proof_height_on_a = mock_client_state.header.height; let message = make_message!( MsgRecvPacket { - packet, - proof_commitment_on_a: CommitmentProofBytes::try_from( - serialized_data - ) - .unwrap(), + packet: packet.clone(), + proof_commitment_on_a: CommitmentProofBytes::try_from(packet.data) + .unwrap(), proof_height_on_a, signer: ibc::Signer::from(authority.pubkey().to_string()) }, @@ -394,6 +385,10 @@ fn anchor_test_deliver() -> Result<()> { println!("These are remaining accounts {:?}", remaining_accounts); + + let escrow_account_balance_before = sol_rpc_client.get_token_account_balance(&escrow_account_key).unwrap(); + let receiver_account_balance_before = sol_rpc_client.get_token_account_balance(&receiver_token_address).unwrap(); + let sig = program .request() .instruction(ComputeBudgetInstruction::set_compute_unit_limit( @@ -406,7 +401,7 @@ fn anchor_test_deliver() -> Result<()> { system_program: system_program::ID, packets, chain, - remaining_accounts, + remaining_accounts: remaining_accounts.clone(), }) .args(instruction::Deliver { message }) .payer(authority.clone()) @@ -416,53 +411,110 @@ fn anchor_test_deliver() -> Result<()> { ..RpcSendTransactionConfig::default() })?; // ? gives us the log messages on the why the tx did fail ( better than unwrap ) - println!("signature for transfer packet: {sig}"); + println!("signature for transfer packet on Source chain: {sig}"); - let mint_info = sol_rpc_client.get_token_supply(&token_mint_key).unwrap(); + let escrow_account_balance_after = sol_rpc_client.get_token_account_balance(&escrow_account_key).unwrap(); + let receiver_account_balance_after = sol_rpc_client.get_token_account_balance(&receiver_token_address).unwrap(); + assert_eq!(((escrow_account_balance_before.ui_amount.unwrap() - escrow_account_balance_after.ui_amount.unwrap()) * 10_f64.powf(mint_info.decimals.into())).round() as u64, TRANSFER_AMOUNT); + assert_eq!(((receiver_account_balance_after.ui_amount.unwrap() - receiver_account_balance_before.ui_amount.unwrap()) * 10_f64.powf(mint_info.decimals.into())).round() as u64, TRANSFER_AMOUNT); - println!("This is the mint information {:?}", mint_info); + /* + * + * On Destination chain + * + */ + + let account_balance_before = sol_rpc_client.get_token_account_balance(&receiver_token_address).unwrap(); + + let packet = construct_packet_from_denom( + port_id.clone(), + channel_id_on_b.clone(), + channel_id_on_a, + channel_id_on_b, + 2, + sender_token_address, + receiver_token_address, + String::from("Tx from destination chain"), + ); + let proof_height_on_a = mock_client_state.header.height; + + let message = make_message!( + MsgRecvPacket { + packet: packet.clone(), + proof_commitment_on_a: CommitmentProofBytes::try_from(packet.data) + .unwrap(), + proof_height_on_a, + signer: ibc::Signer::from(authority.pubkey().to_string()) + }, + ibc::core::ics04_channel::msgs::PacketMsg::Recv, + ibc::core::MsgEnvelope::Packet, + ); + + + let sig = program + .request() + .instruction(ComputeBudgetInstruction::set_compute_unit_limit( + 1_000_000u32, + )) + .accounts(DeliverWithRemainingAccounts { + sender: authority.pubkey(), + storage, + trie, + system_program: system_program::ID, + packets, + chain, + remaining_accounts, + }) + .args(instruction::Deliver { message }) + .payer(authority.clone()) + .signer(&*authority) + .send_with_spinner_and_config(RpcSendTransactionConfig { + skip_preflight: true, + ..RpcSendTransactionConfig::default() + })?; // ? gives us the log messages on the why the tx did fail ( better than unwrap ) + + println!("signature for transfer packet on destination chain: {sig}"); + + let account_balance_after = sol_rpc_client.get_token_account_balance(&receiver_token_address).unwrap(); + assert_eq!(((account_balance_after.ui_amount.unwrap() - account_balance_before.ui_amount.unwrap()) * 10_f64.powf(mint_info.decimals.into())).round() as u64, TRANSFER_AMOUNT); Ok(()) } -// #[test] -// fn internal_test() { -// let authority = Keypair::new(); -// let mut solana_ibc_store = IbcStorage::new(authority.pubkey()); -// let mock_client_state = MockClientState::new(MockHeader::default()); -// let mock_cs_state = MockConsensusState::new(MockHeader::default()); -// let client_id = ClientId::new(mock_client_state.client_type(), 0).unwrap(); -// let msg = MsgCreateClient::new( -// Any::from(mock_client_state), -// Any::from(mock_cs_state), -// ibc::Signer::from(authority.pubkey().to_string()), -// ); -// let messages = ibc::Any { -// type_url: TYPE_URL.to_string(), -// value: msg.encode_vec(), -// }; - -// let all_messages = [messages]; - -// let errors = all_messages.into_iter().fold(vec![], |mut errors, msg| { -// match ibc::core::MsgEnvelope::try_from(msg) { -// Ok(msg) => { -// match ibc::core::dispatch(&mut solana_ibc_store.clone(), &mut solana_ibc_store, msg) -// { -// Ok(()) => (), -// Err(e) => { -// println!("during dispatch"); -// errors.push(e); -// } -// } -// } -// Err(e) => { -// println!("This while converting from msg to msgEnvelope"); -// errors.push(e); -// } -// } -// errors -// }); -// println!("These are the errors"); -// println!("{:?}", errors); -// } +fn construct_packet_from_denom( + port_id: PortId, + denom_channel_id: ChannelId, // Channel id used to define if its source chain or destination chain (in denom) + channel_id_on_a: ChannelId, + channel_id_on_b: ChannelId, + sequence: u64, + sender_token_address: Pubkey, + receiver_token_address: Pubkey, + memo: String, +) -> Packet { + let denom = format!("{port_id}/{denom_channel_id}/{BASE_DENOM}"); + let base_denom: BaseDenom = BaseDenom::from_str(&denom).unwrap(); + let token: BaseCoin = + Coin { denom: base_denom, amount: Amount::from(1000000) }; + + let packet_data = PacketData { + token: token.into(), + sender: ibc::Signer::from(sender_token_address.to_string()), // Should be a token account + receiver: ibc::Signer::from(receiver_token_address.to_string()), // Should be a token account + memo: memo.into(), + }; + + let serialized_data = serde_json::to_vec(&packet_data).unwrap(); + + let packet = Packet { + seq_on_a: sequence.into(), + port_id_on_a: port_id.clone(), + chan_id_on_a: channel_id_on_a, + port_id_on_b: port_id, + chan_id_on_b: channel_id_on_b, + data: serialized_data.clone(), + timeout_height_on_b: TimeoutHeight::Never, + timeout_timestamp_on_b: Timestamp::none(), + }; + + packet +} \ No newline at end of file diff --git a/solana/solana-ibc/programs/solana-ibc/src/transfer/impls.rs b/solana/solana-ibc/programs/solana-ibc/src/transfer/impls.rs index 2cbbb756..5b709618 100644 --- a/solana/solana-ibc/programs/solana-ibc/src/transfer/impls.rs +++ b/solana/solana-ibc/programs/solana-ibc/src/transfer/impls.rs @@ -69,6 +69,7 @@ impl TokenTransferExecutionContext for IbcStorage<'_, '_, '_> { amt.denom.trace_path, amt.denom.base_denom ); + //Find if sender is escrow or receiver let sender_id = Pubkey::from(from); let receiver_id = Pubkey::from(to); let base_denom = amt.denom.base_denom.to_string(); @@ -76,22 +77,26 @@ impl TokenTransferExecutionContext for IbcStorage<'_, '_, '_> { let amount_in_u64 = check_amount_overflow(amount)?; - let (_token_mint_key, bump) = + let (_token_mint_key, _bump) = Pubkey::find_program_address(&[base_denom.as_ref()], &crate::ID); + let (mint_authority_key, mint_authority_bump) = + Pubkey::find_program_address(&[MINT_ESCROW_SEED], &crate::ID); let store = self.borrow(); let accounts = &store.accounts; let sender = get_account_info_from_key(accounts, sender_id)?; let receiver = get_account_info_from_key(accounts, receiver_id)?; + let mint_authority = + get_account_info_from_key(accounts, mint_authority_key)?; let token_program = get_account_info_from_key(accounts, spl_token::ID)?; - let bump_vector = bump.to_le_bytes(); - let inner = vec![base_denom.as_ref(), bump_vector.as_ref()]; + let bump_vector = mint_authority_bump.to_le_bytes(); + let inner = vec![MINT_ESCROW_SEED, bump_vector.as_ref()]; let outer = vec![inner.as_slice()]; // Below is the actual instruction that we are going to send to the Token program. let transfer_instruction = Transfer { from: sender.clone(), to: receiver.clone(), - authority: sender.clone(), + authority: mint_authority.clone(), }; let cpi_ctx = CpiContext::new_with_signer( token_program.clone(), @@ -212,7 +217,8 @@ impl TokenTransferValidationContext for IbcStorage<'_, '_, '_> { port_id: &PortId, channel_id: &ChannelId, ) -> Result { - let seeds = [port_id.as_bytes(), channel_id.as_bytes()]; + let seeds = + [port_id.as_bytes().as_ref(), channel_id.as_bytes().as_ref()]; let (escrow_account_key, _bump) = Pubkey::find_program_address(&seeds, &crate::ID); Ok(AccountId(escrow_account_key)) From 1ec6b1f9a2e7ec04ead7a86f8af7a3d0556fd791 Mon Sep 17 00:00:00 2001 From: dhruvja Date: Tue, 21 Nov 2023 20:39:20 +0530 Subject: [PATCH 34/57] added assert in tests to check token balance for tx --- .../programs/solana-ibc/src/tests.rs | 52 ++++++++++++++----- 1 file changed, 40 insertions(+), 12 deletions(-) diff --git a/solana/solana-ibc/programs/solana-ibc/src/tests.rs b/solana/solana-ibc/programs/solana-ibc/src/tests.rs index e463e6ba..a074a1a3 100644 --- a/solana/solana-ibc/programs/solana-ibc/src/tests.rs +++ b/solana/solana-ibc/programs/solana-ibc/src/tests.rs @@ -330,7 +330,7 @@ fn anchor_test_deliver() -> Result<()> { // Make sure all the accounts needed for transfer are ready ( mint, escrow etc.) // Pass the instruction for transfer - /* + /* * * On Source chain * @@ -385,9 +385,12 @@ fn anchor_test_deliver() -> Result<()> { println!("These are remaining accounts {:?}", remaining_accounts); - - let escrow_account_balance_before = sol_rpc_client.get_token_account_balance(&escrow_account_key).unwrap(); - let receiver_account_balance_before = sol_rpc_client.get_token_account_balance(&receiver_token_address).unwrap(); + + let escrow_account_balance_before = + sol_rpc_client.get_token_account_balance(&escrow_account_key).unwrap(); + let receiver_account_balance_before = sol_rpc_client + .get_token_account_balance(&receiver_token_address) + .unwrap(); let sig = program .request() @@ -413,10 +416,25 @@ fn anchor_test_deliver() -> Result<()> { println!("signature for transfer packet on Source chain: {sig}"); - let escrow_account_balance_after = sol_rpc_client.get_token_account_balance(&escrow_account_key).unwrap(); - let receiver_account_balance_after = sol_rpc_client.get_token_account_balance(&receiver_token_address).unwrap(); - assert_eq!(((escrow_account_balance_before.ui_amount.unwrap() - escrow_account_balance_after.ui_amount.unwrap()) * 10_f64.powf(mint_info.decimals.into())).round() as u64, TRANSFER_AMOUNT); - assert_eq!(((receiver_account_balance_after.ui_amount.unwrap() - receiver_account_balance_before.ui_amount.unwrap()) * 10_f64.powf(mint_info.decimals.into())).round() as u64, TRANSFER_AMOUNT); + let escrow_account_balance_after = + sol_rpc_client.get_token_account_balance(&escrow_account_key).unwrap(); + let receiver_account_balance_after = sol_rpc_client + .get_token_account_balance(&receiver_token_address) + .unwrap(); + assert_eq!( + ((escrow_account_balance_before.ui_amount.unwrap() - + escrow_account_balance_after.ui_amount.unwrap()) * + 10_f64.powf(mint_info.decimals.into())) + .round() as u64, + TRANSFER_AMOUNT + ); + assert_eq!( + ((receiver_account_balance_after.ui_amount.unwrap() - + receiver_account_balance_before.ui_amount.unwrap()) * + 10_f64.powf(mint_info.decimals.into())) + .round() as u64, + TRANSFER_AMOUNT + ); /* * @@ -424,7 +442,9 @@ fn anchor_test_deliver() -> Result<()> { * */ - let account_balance_before = sol_rpc_client.get_token_account_balance(&receiver_token_address).unwrap(); + let account_balance_before = sol_rpc_client + .get_token_account_balance(&receiver_token_address) + .unwrap(); let packet = construct_packet_from_denom( port_id.clone(), @@ -475,8 +495,16 @@ fn anchor_test_deliver() -> Result<()> { println!("signature for transfer packet on destination chain: {sig}"); - let account_balance_after = sol_rpc_client.get_token_account_balance(&receiver_token_address).unwrap(); - assert_eq!(((account_balance_after.ui_amount.unwrap() - account_balance_before.ui_amount.unwrap()) * 10_f64.powf(mint_info.decimals.into())).round() as u64, TRANSFER_AMOUNT); + let account_balance_after = sol_rpc_client + .get_token_account_balance(&receiver_token_address) + .unwrap(); + assert_eq!( + ((account_balance_after.ui_amount.unwrap() - + account_balance_before.ui_amount.unwrap()) * + 10_f64.powf(mint_info.decimals.into())) + .round() as u64, + TRANSFER_AMOUNT + ); Ok(()) } @@ -517,4 +545,4 @@ fn construct_packet_from_denom( }; packet -} \ No newline at end of file +} From 06047a34b011afacd935b4e9488744ed227345cb Mon Sep 17 00:00:00 2001 From: dhruvja Date: Thu, 23 Nov 2023 11:19:01 +0530 Subject: [PATCH 35/57] fix clippy --- solana/solana-ibc/programs/solana-ibc/src/transfer/impls.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/solana/solana-ibc/programs/solana-ibc/src/transfer/impls.rs b/solana/solana-ibc/programs/solana-ibc/src/transfer/impls.rs index 5b709618..7bfbd215 100644 --- a/solana/solana-ibc/programs/solana-ibc/src/transfer/impls.rs +++ b/solana/solana-ibc/programs/solana-ibc/src/transfer/impls.rs @@ -218,7 +218,7 @@ impl TokenTransferValidationContext for IbcStorage<'_, '_, '_> { channel_id: &ChannelId, ) -> Result { let seeds = - [port_id.as_bytes().as_ref(), channel_id.as_bytes().as_ref()]; + [port_id.as_bytes(), channel_id.as_bytes()]; let (escrow_account_key, _bump) = Pubkey::find_program_address(&seeds, &crate::ID); Ok(AccountId(escrow_account_key)) From 759575f88b6ef1b62590ac4b253db4ff7ee2ccb7 Mon Sep 17 00:00:00 2001 From: dhruvja Date: Fri, 24 Nov 2023 11:34:43 +0530 Subject: [PATCH 36/57] fmt --- solana/solana-ibc/programs/solana-ibc/src/transfer/impls.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/solana/solana-ibc/programs/solana-ibc/src/transfer/impls.rs b/solana/solana-ibc/programs/solana-ibc/src/transfer/impls.rs index 7bfbd215..0b4bd1aa 100644 --- a/solana/solana-ibc/programs/solana-ibc/src/transfer/impls.rs +++ b/solana/solana-ibc/programs/solana-ibc/src/transfer/impls.rs @@ -217,8 +217,7 @@ impl TokenTransferValidationContext for IbcStorage<'_, '_, '_> { port_id: &PortId, channel_id: &ChannelId, ) -> Result { - let seeds = - [port_id.as_bytes(), channel_id.as_bytes()]; + let seeds = [port_id.as_bytes(), channel_id.as_bytes()]; let (escrow_account_key, _bump) = Pubkey::find_program_address(&seeds, &crate::ID); Ok(AccountId(escrow_account_key)) From 83c9d13525755aa2819e970a369ce4198ac7f415 Mon Sep 17 00:00:00 2001 From: dhruvja Date: Sat, 25 Nov 2023 01:54:20 +0530 Subject: [PATCH 37/57] bump anchor-spl to lts --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index b9385904..7274f00d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -23,7 +23,7 @@ incremental = false codegen-units = 1 [workspace.dependencies] -anchor-spl = "0.28.0" +anchor-spl = "0.29.0" uint = "0.9.5" anchor-lang = {version = "0.29.0", features = ["init-if-needed"]} ascii = "1.1.0" From 9d5212eb163dc08ccadf755db82c8aa70cb7f8a4 Mon Sep 17 00:00:00 2001 From: dhruvja Date: Sun, 26 Nov 2023 22:33:22 +0530 Subject: [PATCH 38/57] added an enum for accountId --- .vscode/settings.json | 5 + .../solana-ibc/programs/solana-ibc/src/lib.rs | 8 +- .../programs/solana-ibc/src/mocks.rs | 2 +- .../programs/solana-ibc/src/storage/ids.rs | 2 + .../programs/solana-ibc/src/tests.rs | 52 ++++-- .../programs/solana-ibc/src/transfer/impls.rs | 164 ++++++++++++++---- 6 files changed, 181 insertions(+), 52 deletions(-) create mode 100644 .vscode/settings.json diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 00000000..034acdf7 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,5 @@ +{ + "rust-analyzer.linkedProjects": [ + "./solana/solana-ibc/programs/solana-ibc/Cargo.toml" + ] +} \ No newline at end of file diff --git a/solana/solana-ibc/programs/solana-ibc/src/lib.rs b/solana/solana-ibc/programs/solana-ibc/src/lib.rs index 26e919a7..505a2c09 100644 --- a/solana/solana-ibc/programs/solana-ibc/src/lib.rs +++ b/solana/solana-ibc/programs/solana-ibc/src/lib.rs @@ -277,18 +277,18 @@ pub struct MockDeliver<'info> { receiver: AccountInfo<'info>, /// The account holding private IBC storage. - #[account(mut, seeds = [SOLANA_IBC_STORAGE_SEED],bump, realloc = 10240, realloc::payer = sender, realloc::zero = false)] + #[account(mut, seeds = [SOLANA_IBC_STORAGE_SEED],bump)] storage: Box>, /// The account holding provable IBC storage, i.e. the trie. /// /// CHECK: Account’s owner is checked by [`storage::get_provable_from`] /// function. - #[account(init_if_needed, payer = sender, seeds = [TRIE_SEED], bump, space = 10240)] + #[account(mut , seeds = [TRIE_SEED], bump)] trie: UncheckedAccount<'info>, /// The account holding packets. - #[account(init_if_needed, payer = sender, seeds = [PACKET_SEED], bump, space = 10240)] + #[account(mut , seeds = [PACKET_SEED], bump)] packets: Box>, /// The below accounts are being created for testing purposes only. @@ -299,7 +299,7 @@ pub struct MockDeliver<'info> { mint_authority: UncheckedAccount<'info>, #[account(init_if_needed, payer = sender, seeds = [base_denom.as_bytes()], bump, mint::decimals = 6, mint::authority = mint_authority)] token_mint: Box>, - #[account(init_if_needed, payer = sender, seeds = [port_id.as_bytes(), channel_id_on_b.as_bytes()], bump, token::mint = token_mint, token::authority = mint_authority)] + #[account(init_if_needed, payer = sender, seeds = [port_id.as_bytes(), channel_id_on_b.as_bytes(), base_denom.as_bytes()], bump, token::mint = token_mint, token::authority = mint_authority)] escrow_account: Box>, #[account(init_if_needed, payer = sender, associated_token::mint = token_mint, associated_token::authority = sender)] sender_token_account: Box>, diff --git a/solana/solana-ibc/programs/solana-ibc/src/mocks.rs b/solana/solana-ibc/programs/solana-ibc/src/mocks.rs index 9ba0f460..ee3eb6bd 100644 --- a/solana/solana-ibc/programs/solana-ibc/src/mocks.rs +++ b/solana/solana-ibc/programs/solana-ibc/src/mocks.rs @@ -179,7 +179,7 @@ pub fn mock_deliver_impl( .unwrap(); // Minting some tokens to the escrow so that he can do the transfer - let bump_vector = ctx.bumps.get("mint_authority").unwrap().to_le_bytes(); + let bump_vector = ctx.bumps.mint_authority.to_le_bytes(); let inner = vec![MINT_ESCROW_SEED, bump_vector.as_ref()]; let outer = vec![inner.as_slice()]; diff --git a/solana/solana-ibc/programs/solana-ibc/src/storage/ids.rs b/solana/solana-ibc/programs/solana-ibc/src/storage/ids.rs index dd9ebe89..3e0310d5 100644 --- a/solana/solana-ibc/programs/solana-ibc/src/storage/ids.rs +++ b/solana/solana-ibc/programs/solana-ibc/src/storage/ids.rs @@ -160,8 +160,10 @@ impl PortChannelPK { }) } + #[allow(dead_code)] pub fn port_id(&self) -> ibc::PortId { ibc::PortId::from(&self.port_key) } + #[allow(dead_code)] pub fn channel_id(&self) -> ibc::ChannelId { ibc::ChannelId::new(self.channel_idx.into()) } diff --git a/solana/solana-ibc/programs/solana-ibc/src/tests.rs b/solana/solana-ibc/programs/solana-ibc/src/tests.rs index a074a1a3..b2655a79 100644 --- a/solana/solana-ibc/programs/solana-ibc/src/tests.rs +++ b/solana/solana-ibc/programs/solana-ibc/src/tests.rs @@ -77,7 +77,7 @@ pub struct DeliverWithRemainingAccounts { packets: Pubkey, chain: Pubkey, system_program: Pubkey, - remaining_accounts: Vec, + remaining_accounts: Vec, } impl ToAccountMetas for DeliverWithRemainingAccounts { @@ -118,9 +118,8 @@ impl ToAccountMetas for DeliverWithRemainingAccounts { }, ]; - let remaining = self.remaining_accounts.iter().map(|&account| { - AccountMeta { pubkey: account, is_signer: false, is_writable: true } - }); + let remaining = + self.remaining_accounts.iter().map(|account| account.clone()); accounts.into_iter().chain(remaining).collect::>() } @@ -266,8 +265,11 @@ fn anchor_test_deliver() -> Result<()> { let receiver = Keypair::new(); - let seeds = - [port_id.as_bytes().as_ref(), channel_id_on_b.as_bytes().as_ref()]; + let seeds = [ + port_id.as_bytes().as_ref(), + channel_id_on_b.as_bytes().as_ref(), + BASE_DENOM.as_bytes().as_ref(), + ]; let (escrow_account_key, _bump) = Pubkey::find_program_address(&seeds, &crate::ID); let (token_mint_key, _bump) = @@ -375,17 +377,40 @@ fn anchor_test_deliver() -> Result<()> { */ let remaining_accounts = vec![ - sender_token_address, - receiver_token_address, - token_mint_key, - escrow_account_key, - mint_authority_key, - anchor_spl::token::ID, + AccountMeta { + pubkey: sender_token_address, + is_signer: false, + is_writable: true, + }, + AccountMeta { + pubkey: receiver_token_address, + is_signer: false, + is_writable: true, + }, + AccountMeta { + pubkey: token_mint_key, + is_signer: false, + is_writable: true, + }, + AccountMeta { + pubkey: escrow_account_key, + is_signer: false, + is_writable: true, + }, + AccountMeta { + pubkey: mint_authority_key, + is_signer: false, + is_writable: true, + }, + AccountMeta { + pubkey: anchor_spl::token::ID, + is_signer: false, + is_writable: true, + }, ]; println!("These are remaining accounts {:?}", remaining_accounts); - let escrow_account_balance_before = sol_rpc_client.get_token_account_balance(&escrow_account_key).unwrap(); let receiver_account_balance_before = sol_rpc_client @@ -470,7 +495,6 @@ fn anchor_test_deliver() -> Result<()> { ibc::core::MsgEnvelope::Packet, ); - let sig = program .request() .instruction(ComputeBudgetInstruction::set_compute_unit_limit( diff --git a/solana/solana-ibc/programs/solana-ibc/src/transfer/impls.rs b/solana/solana-ibc/programs/solana-ibc/src/transfer/impls.rs index 0b4bd1aa..57913b8b 100644 --- a/solana/solana-ibc/programs/solana-ibc/src/transfer/impls.rs +++ b/solana/solana-ibc/programs/solana-ibc/src/transfer/impls.rs @@ -2,7 +2,8 @@ use std::str::FromStr; use anchor_lang::prelude::{AccountInfo, CpiContext, Pubkey}; use anchor_lang::solana_program::msg; -use anchor_spl::token::{spl_token, Burn, MintTo, Transfer}; +use anchor_lang::AccountDeserialize; +use anchor_spl::token::{spl_token, Burn, MintTo, TokenAccount, Transfer}; use ibc::applications::transfer::context::{ TokenTransferExecutionContext, TokenTransferValidationContext, }; @@ -10,9 +11,10 @@ use ibc::applications::transfer::error::TokenTransferError; use ibc::applications::transfer::{Amount, PrefixedCoin}; use ibc::core::ics24_host::identifier::{ChannelId, PortId}; use primitive_types::U256; +use strum::Display; use uint::FromDecStrErr; -// use crate::module_holder::IbcStorage<'_,'_>; +use crate::storage::ids::PortChannelPK; use crate::{storage::IbcStorage, MINT_ESCROW_SEED}; #[derive(Clone, PartialEq, Eq, derive_more::From)] @@ -22,7 +24,7 @@ impl TryFrom for AccountId { type Error = ::Err; fn try_from(value: ibc::Signer) -> Result { - Pubkey::from_str(value.as_ref()).map(Self) + Pubkey::try_from(value.as_ref()).map(Self) } } @@ -54,6 +56,61 @@ impl From<&AccountId> for Pubkey { fn from(value: &AccountId) -> Self { value.0 } } +/// Structure to identify if the account is escrow or not. If it is escrow account, we derive the escrow account using port-id, channel-id and denom. +#[derive(Clone, Display, PartialEq, Eq, derive_more::From)] +pub enum AccountIdx { + Signer(AccountId), + Escrow(PortChannelPK), +} + +impl TryFrom for AccountIdx { + type Error = ::Err; + + fn try_from(value: ibc::Signer) -> Result { + Ok(Self::Signer(AccountId::try_from(value).unwrap())) + } +} + +#[derive(Debug)] +pub enum InvalidAccountIdVariant { + NotEscrowAccount, + NotSignerAccount, +} + +impl AccountIdx { + pub fn get_escrow_account( + &self, + denom: String, + ) -> Result { + let port_channel = match self { + AccountIdx::Escrow(pk) => pk, + AccountIdx::Signer(_) => { + return Err(InvalidAccountIdVariant::NotEscrowAccount) + } + }; + let channel_id = port_channel.channel_id(); + let port_id = port_channel.port_id(); + let seeds = + [port_id.as_bytes(), channel_id.as_bytes(), denom.as_bytes()]; + let (escrow_account_key, _bump) = + Pubkey::find_program_address(&seeds, &crate::ID); + Ok(escrow_account_key) + } +} + +impl TryFrom<&AccountIdx> for Pubkey { + type Error = InvalidAccountIdVariant; + + fn try_from(value: &AccountIdx) -> Result { + match value { + AccountIdx::Signer(signer) => Ok(signer.0), + AccountIdx::Escrow(_) => { + Err(InvalidAccountIdVariant::NotSignerAccount) + } + } + } +} + impl TokenTransferExecutionContext for IbcStorage<'_, '_, '_> { fn send_coins_execute( &mut self, @@ -69,42 +126,82 @@ impl TokenTransferExecutionContext for IbcStorage<'_, '_, '_> { amt.denom.trace_path, amt.denom.base_denom ); - //Find if sender is escrow or receiver - let sender_id = Pubkey::from(from); - let receiver_id = Pubkey::from(to); let base_denom = amt.denom.base_denom.to_string(); - let amount = amt.amount; + let sender_id = Pubkey::try_from(from).unwrap_or_else(|_| { + from.get_escrow_account(base_denom.clone()).unwrap() + }); + let receiver_id = Pubkey::try_from(to).unwrap_or_else(|_| { + to.get_escrow_account(base_denom.clone()).unwrap() + }); + let amount = amt.amount; let amount_in_u64 = check_amount_overflow(amount)?; let (_token_mint_key, _bump) = Pubkey::find_program_address(&[base_denom.as_ref()], &crate::ID); - let (mint_authority_key, mint_authority_bump) = - Pubkey::find_program_address(&[MINT_ESCROW_SEED], &crate::ID); let store = self.borrow(); let accounts = &store.accounts; + let sender = get_account_info_from_key(accounts, sender_id)?; let receiver = get_account_info_from_key(accounts, receiver_id)?; - let mint_authority = - get_account_info_from_key(accounts, mint_authority_key)?; let token_program = get_account_info_from_key(accounts, spl_token::ID)?; - let bump_vector = mint_authority_bump.to_le_bytes(); - let inner = vec![MINT_ESCROW_SEED, bump_vector.as_ref()]; - let outer = vec![inner.as_slice()]; - // Below is the actual instruction that we are going to send to the Token program. - let transfer_instruction = Transfer { - from: sender.clone(), - to: receiver.clone(), - authority: mint_authority.clone(), - }; - let cpi_ctx = CpiContext::new_with_signer( - token_program.clone(), - transfer_instruction, - outer.as_slice(), //signer PDA - ); + if matches!(from, AccountIdx::Escrow(_)) { + let (mint_authority_key, mint_authority_bump) = + Pubkey::find_program_address(&[MINT_ESCROW_SEED], &crate::ID); + + let mint_authority = + get_account_info_from_key(accounts, mint_authority_key)?; + + let bump_vector = mint_authority_bump.to_le_bytes(); + let inner = vec![MINT_ESCROW_SEED, bump_vector.as_ref()]; + let outer = vec![inner.as_slice()]; + + // Below is the actual instruction that we are going to send to the Token program. + let transfer_instruction = Transfer { + from: sender.clone(), + to: receiver.clone(), + authority: mint_authority.clone(), + }; + let cpi_ctx = CpiContext::new_with_signer( + token_program.clone(), + transfer_instruction, + outer.as_slice(), //signer PDA + ); + + anchor_spl::token::transfer(cpi_ctx, amount_in_u64).unwrap(); + } else { + let sender_token_account = + TokenAccount::try_deserialize(&mut &sender.data.borrow()[..]) + .unwrap(); + let sender_token_account_owner = sender_token_account.owner; + let authority = get_account_info_from_key( + accounts, + sender_token_account_owner, + )?; + + // PDA generated so that we can sign the tx + let (_mint_authority_key, mint_authority_bump) = + Pubkey::find_program_address(&[MINT_ESCROW_SEED], &crate::ID); + let bump_vector = mint_authority_bump.to_le_bytes(); + let inner = vec![MINT_ESCROW_SEED, bump_vector.as_ref()]; + let outer = vec![inner.as_slice()]; + + // Below is the actual instruction that we are going to send to the Token program. + let transfer_instruction = Transfer { + from: sender.clone(), + to: receiver.clone(), + authority: authority.clone(), + }; + let cpi_ctx = CpiContext::new_with_signer( + token_program.clone(), + transfer_instruction, + outer.as_slice(), //signer PDA + ); + + anchor_spl::token::transfer(cpi_ctx, amount_in_u64).unwrap(); + } - anchor_spl::token::transfer(cpi_ctx, amount_in_u64).unwrap(); Ok(()) } @@ -119,7 +216,8 @@ impl TokenTransferExecutionContext for IbcStorage<'_, '_, '_> { amt.denom.trace_path, amt.denom.base_denom ); - let receiver_id = Pubkey::from(account); + let receiver_id = Pubkey::try_from(account) + .map_err(|_| TokenTransferError::ParseAccountFailure)?; let base_denom = amt.denom.base_denom.to_string(); let amount = amt.amount; @@ -168,7 +266,8 @@ impl TokenTransferExecutionContext for IbcStorage<'_, '_, '_> { amt.denom.trace_path, amt.denom.base_denom ); - let burner_id = Pubkey::from(account); + let burner_id = Pubkey::try_from(account) + .map_err(|_| TokenTransferError::ParseAccountFailure)?; let base_denom = amt.denom.base_denom.to_string(); let amount = amt.amount; let amount_in_u64 = check_amount_overflow(amount)?; @@ -206,7 +305,7 @@ impl TokenTransferExecutionContext for IbcStorage<'_, '_, '_> { } impl TokenTransferValidationContext for IbcStorage<'_, '_, '_> { - type AccountId = AccountId; + type AccountId = AccountIdx; fn get_port(&self) -> Result { Ok(PortId::transfer()) @@ -217,10 +316,9 @@ impl TokenTransferValidationContext for IbcStorage<'_, '_, '_> { port_id: &PortId, channel_id: &ChannelId, ) -> Result { - let seeds = [port_id.as_bytes(), channel_id.as_bytes()]; - let (escrow_account_key, _bump) = - Pubkey::find_program_address(&seeds, &crate::ID); - Ok(AccountId(escrow_account_key)) + Ok(AccountIdx::Escrow( + PortChannelPK::try_from(port_id, channel_id).unwrap(), + )) } fn can_send_coins(&self) -> Result<(), TokenTransferError> { From d47ca3e2180516d948ba0fd4d3e6862f6269e251 Mon Sep 17 00:00:00 2001 From: dhruvja Date: Sun, 26 Nov 2023 22:34:42 +0530 Subject: [PATCH 39/57] fmt --- solana/solana-ibc/programs/solana-ibc/src/transfer/impls.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/solana/solana-ibc/programs/solana-ibc/src/transfer/impls.rs b/solana/solana-ibc/programs/solana-ibc/src/transfer/impls.rs index 57913b8b..73f75859 100644 --- a/solana/solana-ibc/programs/solana-ibc/src/transfer/impls.rs +++ b/solana/solana-ibc/programs/solana-ibc/src/transfer/impls.rs @@ -15,7 +15,8 @@ use strum::Display; use uint::FromDecStrErr; use crate::storage::ids::PortChannelPK; -use crate::{storage::IbcStorage, MINT_ESCROW_SEED}; +use crate::storage::IbcStorage; +use crate::MINT_ESCROW_SEED; #[derive(Clone, PartialEq, Eq, derive_more::From)] pub struct AccountId(Pubkey); From f027dec2314ac301dea45acbaaa26ea44f549562 Mon Sep 17 00:00:00 2001 From: Michal Nazarewicz Date: Sun, 26 Nov 2023 20:45:46 +0100 Subject: [PATCH 40/57] Delete .vscode/settings.json Signed-off-by: Michal Nazarewicz --- .vscode/settings.json | 5 ----- 1 file changed, 5 deletions(-) delete mode 100644 .vscode/settings.json diff --git a/.vscode/settings.json b/.vscode/settings.json deleted file mode 100644 index 034acdf7..00000000 --- a/.vscode/settings.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "rust-analyzer.linkedProjects": [ - "./solana/solana-ibc/programs/solana-ibc/Cargo.toml" - ] -} \ No newline at end of file From 349ae4f5fa8d8afa9537ef5022d3a54c84658b42 Mon Sep 17 00:00:00 2001 From: Michal Nazarewicz Date: Sun, 26 Nov 2023 20:47:20 +0100 Subject: [PATCH 41/57] Update Cargo.toml Signed-off-by: Michal Nazarewicz --- Cargo.toml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 7274f00d..d4165414 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -23,9 +23,8 @@ incremental = false codegen-units = 1 [workspace.dependencies] -anchor-spl = "0.29.0" -uint = "0.9.5" anchor-lang = {version = "0.29.0", features = ["init-if-needed"]} +anchor-spl = "0.29.0" ascii = "1.1.0" base64 = { version = "0.21", default-features = false, features = ["alloc"] } borsh = { version = "0.10.3", default-features = false } @@ -35,6 +34,7 @@ hex-literal = "0.4.1" ibc = { version = "0.47.0", default-features = false, features = ["borsh", "serde"] } ibc-proto = { version = "0.37.1", default-features = false } pretty_assertions = "1.4.0" +primitive-types = "0.12.2" rand = { version = "0.8.5" } serde = "1" serde_json = "1" @@ -42,9 +42,9 @@ sha2 = { version = "0.10.7", default-features = false } solana-client = "1.16.14" solana-program = "1.16.14" solana-sdk = "1.16.14" -strum = { version = "0.25.0", default-features = false, features = ["derive"] } spl-associated-token-account = "2.2.0" -primitive-types = "0.12.2" +strum = { version = "0.25.0", default-features = false, features = ["derive"] } +uint = "0.9.5" blockchain = { path = "common/blockchain" } lib = { path = "common/lib" } From da0e5a0f40ceb121245cf19bca756e0a3015828f Mon Sep 17 00:00:00 2001 From: dhruvja Date: Mon, 27 Nov 2023 11:15:22 +0530 Subject: [PATCH 42/57] made const as public and better comments --- .../solana-ibc/programs/solana-ibc/src/lib.rs | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/solana/solana-ibc/programs/solana-ibc/src/lib.rs b/solana/solana-ibc/programs/solana-ibc/src/lib.rs index 505a2c09..d7ebde39 100644 --- a/solana/solana-ibc/programs/solana-ibc/src/lib.rs +++ b/solana/solana-ibc/programs/solana-ibc/src/lib.rs @@ -18,11 +18,11 @@ use ibc::core::MsgEnvelope; use mocks::mock_deliver_impl; use storage::IbcPackets; -const CHAIN_SEED: &[u8] = b"chain"; -const PACKET_SEED: &[u8] = b"packet"; -const SOLANA_IBC_STORAGE_SEED: &[u8] = b"private"; -const TRIE_SEED: &[u8] = b"trie"; -const MINT_ESCROW_SEED: &[u8] = b"mint_escrow"; +pub const CHAIN_SEED: &[u8] = b"chain"; +pub const PACKET_SEED: &[u8] = b"packet"; +pub const SOLANA_IBC_STORAGE_SEED: &[u8] = b"private"; +pub const TRIE_SEED: &[u8] = b"trie"; +pub const MINT_ESCROW_SEED: &[u8] = b"mint_escrow"; declare_id!("EnfDJsAK7BGgetnmKzBx86CsgC5kfSPcsktFCQ4YLC81"); @@ -36,7 +36,7 @@ mod execution_context; mod host; #[cfg(feature = "mocks")] mod mocks; -mod storage; +pub mod storage; #[cfg(test)] mod tests; mod transfer; @@ -130,7 +130,7 @@ pub mod solana_ibc { // Before anything else, try generating a new guest block. However, if // that fails it’s not an error condition. We do this at the beginning // of any request. - // ctx.accounts.chain.maybe_generate_block(&provable, Some(host_head))?; + ctx.accounts.chain.maybe_generate_block(&provable, Some(host_head))?; let mut store = storage::IbcStorage::new(storage::IbcStorageInner { private, @@ -167,7 +167,8 @@ pub mod solana_ibc { Ok(()) } - /// This method is called to set up connection, channel and store the next sequence. Will panic if called without `[mocks]` feature + /// Called to set up a connection, channel and store the next + /// sequence. Will panic if called without `mocks` feature. #[allow(unused_variables)] pub fn mock_deliver( ctx: Context, From 8ab4b03a6c80bc4faaa668dbfc1196aff25ae299 Mon Sep 17 00:00:00 2001 From: dhruvja Date: Mon, 27 Nov 2023 11:23:43 +0530 Subject: [PATCH 43/57] remove old accountId in transfers --- .../programs/solana-ibc/src/transfer/impls.rs | 45 ++----------------- 1 file changed, 3 insertions(+), 42 deletions(-) diff --git a/solana/solana-ibc/programs/solana-ibc/src/transfer/impls.rs b/solana/solana-ibc/programs/solana-ibc/src/transfer/impls.rs index 73f75859..5420671f 100644 --- a/solana/solana-ibc/programs/solana-ibc/src/transfer/impls.rs +++ b/solana/solana-ibc/programs/solana-ibc/src/transfer/impls.rs @@ -18,49 +18,10 @@ use crate::storage::ids::PortChannelPK; use crate::storage::IbcStorage; use crate::MINT_ESCROW_SEED; -#[derive(Clone, PartialEq, Eq, derive_more::From)] -pub struct AccountId(Pubkey); - -impl TryFrom for AccountId { - type Error = ::Err; - - fn try_from(value: ibc::Signer) -> Result { - Pubkey::try_from(value.as_ref()).map(Self) - } -} - -impl PartialEq for AccountId { - #[inline] - fn eq(&self, rhs: &Pubkey) -> bool { &self.0 == rhs } -} - -impl PartialEq for Pubkey { - #[inline] - fn eq(&self, rhs: &AccountId) -> bool { self == &rhs.0 } -} - -impl core::fmt::Debug for AccountId { - #[inline] - fn fmt(&self, fmtr: &mut core::fmt::Formatter) -> core::fmt::Result { - self.0.fmt(fmtr) - } -} - -impl core::fmt::Display for AccountId { - #[inline] - fn fmt(&self, fmtr: &mut core::fmt::Formatter) -> core::fmt::Result { - self.0.fmt(fmtr) - } -} - -impl From<&AccountId> for Pubkey { - fn from(value: &AccountId) -> Self { value.0 } -} - /// Structure to identify if the account is escrow or not. If it is escrow account, we derive the escrow account using port-id, channel-id and denom. #[derive(Clone, Display, PartialEq, Eq, derive_more::From)] pub enum AccountIdx { - Signer(AccountId), + Signer(Pubkey), Escrow(PortChannelPK), } @@ -68,7 +29,7 @@ impl TryFrom for AccountIdx { type Error = ::Err; fn try_from(value: ibc::Signer) -> Result { - Ok(Self::Signer(AccountId::try_from(value).unwrap())) + Ok(Self::Signer(Pubkey::try_from(value.as_ref())?)) } } @@ -104,7 +65,7 @@ impl TryFrom<&AccountIdx> for Pubkey { fn try_from(value: &AccountIdx) -> Result { match value { - AccountIdx::Signer(signer) => Ok(signer.0), + AccountIdx::Signer(signer) => Ok(*signer), AccountIdx::Escrow(_) => { Err(InvalidAccountIdVariant::NotSignerAccount) } From a43f91a1ede1a86e666e70a11e6e5f0656ee41ed Mon Sep 17 00:00:00 2001 From: dhruvja Date: Mon, 27 Nov 2023 11:26:14 +0530 Subject: [PATCH 44/57] rename AccountIdx to AccountId --- .../programs/solana-ibc/src/transfer/impls.rs | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/solana/solana-ibc/programs/solana-ibc/src/transfer/impls.rs b/solana/solana-ibc/programs/solana-ibc/src/transfer/impls.rs index 5420671f..96ba0746 100644 --- a/solana/solana-ibc/programs/solana-ibc/src/transfer/impls.rs +++ b/solana/solana-ibc/programs/solana-ibc/src/transfer/impls.rs @@ -20,12 +20,12 @@ use crate::MINT_ESCROW_SEED; /// Structure to identify if the account is escrow or not. If it is escrow account, we derive the escrow account using port-id, channel-id and denom. #[derive(Clone, Display, PartialEq, Eq, derive_more::From)] -pub enum AccountIdx { +pub enum AccountId { Signer(Pubkey), Escrow(PortChannelPK), } -impl TryFrom for AccountIdx { +impl TryFrom for AccountId { type Error = ::Err; fn try_from(value: ibc::Signer) -> Result { @@ -39,14 +39,14 @@ pub enum InvalidAccountIdVariant { NotSignerAccount, } -impl AccountIdx { +impl AccountId { pub fn get_escrow_account( &self, denom: String, ) -> Result { let port_channel = match self { - AccountIdx::Escrow(pk) => pk, - AccountIdx::Signer(_) => { + AccountId::Escrow(pk) => pk, + AccountId::Signer(_) => { return Err(InvalidAccountIdVariant::NotEscrowAccount) } }; @@ -60,13 +60,13 @@ impl AccountIdx { } } -impl TryFrom<&AccountIdx> for Pubkey { +impl TryFrom<&AccountId> for Pubkey { type Error = InvalidAccountIdVariant; - fn try_from(value: &AccountIdx) -> Result { + fn try_from(value: &AccountId) -> Result { match value { - AccountIdx::Signer(signer) => Ok(*signer), - AccountIdx::Escrow(_) => { + AccountId::Signer(signer) => Ok(*signer), + AccountId::Escrow(_) => { Err(InvalidAccountIdVariant::NotSignerAccount) } } @@ -108,7 +108,7 @@ impl TokenTransferExecutionContext for IbcStorage<'_, '_, '_> { let receiver = get_account_info_from_key(accounts, receiver_id)?; let token_program = get_account_info_from_key(accounts, spl_token::ID)?; - if matches!(from, AccountIdx::Escrow(_)) { + if matches!(from, AccountId::Escrow(_)) { let (mint_authority_key, mint_authority_bump) = Pubkey::find_program_address(&[MINT_ESCROW_SEED], &crate::ID); @@ -267,7 +267,7 @@ impl TokenTransferExecutionContext for IbcStorage<'_, '_, '_> { } impl TokenTransferValidationContext for IbcStorage<'_, '_, '_> { - type AccountId = AccountIdx; + type AccountId = AccountId; fn get_port(&self) -> Result { Ok(PortId::transfer()) @@ -278,7 +278,7 @@ impl TokenTransferValidationContext for IbcStorage<'_, '_, '_> { port_id: &PortId, channel_id: &ChannelId, ) -> Result { - Ok(AccountIdx::Escrow( + Ok(AccountId::Escrow( PortChannelPK::try_from(port_id, channel_id).unwrap(), )) } From 307fab9ea38539b62789347ea9c306bcb143fca5 Mon Sep 17 00:00:00 2001 From: dhruvja Date: Mon, 27 Nov 2023 11:27:47 +0530 Subject: [PATCH 45/57] use str instead of string for denom while getting escrow acc --- solana/solana-ibc/programs/solana-ibc/src/transfer/impls.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/solana/solana-ibc/programs/solana-ibc/src/transfer/impls.rs b/solana/solana-ibc/programs/solana-ibc/src/transfer/impls.rs index 96ba0746..5ed9b215 100644 --- a/solana/solana-ibc/programs/solana-ibc/src/transfer/impls.rs +++ b/solana/solana-ibc/programs/solana-ibc/src/transfer/impls.rs @@ -42,7 +42,7 @@ pub enum InvalidAccountIdVariant { impl AccountId { pub fn get_escrow_account( &self, - denom: String, + denom: &str, ) -> Result { let port_channel = match self { AccountId::Escrow(pk) => pk, @@ -90,10 +90,10 @@ impl TokenTransferExecutionContext for IbcStorage<'_, '_, '_> { ); let base_denom = amt.denom.base_denom.to_string(); let sender_id = Pubkey::try_from(from).unwrap_or_else(|_| { - from.get_escrow_account(base_denom.clone()).unwrap() + from.get_escrow_account(base_denom.as_str()).unwrap() }); let receiver_id = Pubkey::try_from(to).unwrap_or_else(|_| { - to.get_escrow_account(base_denom.clone()).unwrap() + to.get_escrow_account(base_denom.as_str()).unwrap() }); let amount = amt.amount; From f1d7845cb9c36f7d21605b7303d639327ac75760 Mon Sep 17 00:00:00 2001 From: dhruvja Date: Mon, 27 Nov 2023 11:30:29 +0530 Subject: [PATCH 46/57] better seeds --- .../programs/solana-ibc/src/transfer/impls.rs | 24 +++++++++---------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/solana/solana-ibc/programs/solana-ibc/src/transfer/impls.rs b/solana/solana-ibc/programs/solana-ibc/src/transfer/impls.rs index 5ed9b215..3af764db 100644 --- a/solana/solana-ibc/programs/solana-ibc/src/transfer/impls.rs +++ b/solana/solana-ibc/programs/solana-ibc/src/transfer/impls.rs @@ -96,8 +96,7 @@ impl TokenTransferExecutionContext for IbcStorage<'_, '_, '_> { to.get_escrow_account(base_denom.as_str()).unwrap() }); - let amount = amt.amount; - let amount_in_u64 = check_amount_overflow(amount)?; + let amount_in_u64 = check_amount_overflow(amt.amount)?; let (_token_mint_key, _bump) = Pubkey::find_program_address(&[base_denom.as_ref()], &crate::ID); @@ -116,8 +115,9 @@ impl TokenTransferExecutionContext for IbcStorage<'_, '_, '_> { get_account_info_from_key(accounts, mint_authority_key)?; let bump_vector = mint_authority_bump.to_le_bytes(); - let inner = vec![MINT_ESCROW_SEED, bump_vector.as_ref()]; - let outer = vec![inner.as_slice()]; + let seeds = [MINT_ESCROW_SEED, bump_vector.as_ref()]; + let seeds = seeds.as_ref(); + let seeds = core::slice::from_ref(&seeds); // Below is the actual instruction that we are going to send to the Token program. let transfer_instruction = Transfer { @@ -128,7 +128,7 @@ impl TokenTransferExecutionContext for IbcStorage<'_, '_, '_> { let cpi_ctx = CpiContext::new_with_signer( token_program.clone(), transfer_instruction, - outer.as_slice(), //signer PDA + seeds, //signer PDA ); anchor_spl::token::transfer(cpi_ctx, amount_in_u64).unwrap(); @@ -146,8 +146,9 @@ impl TokenTransferExecutionContext for IbcStorage<'_, '_, '_> { let (_mint_authority_key, mint_authority_bump) = Pubkey::find_program_address(&[MINT_ESCROW_SEED], &crate::ID); let bump_vector = mint_authority_bump.to_le_bytes(); - let inner = vec![MINT_ESCROW_SEED, bump_vector.as_ref()]; - let outer = vec![inner.as_slice()]; + let seeds = [MINT_ESCROW_SEED, bump_vector.as_ref()]; + let seeds = seeds.as_ref(); + let seeds = core::slice::from_ref(&seeds); // Below is the actual instruction that we are going to send to the Token program. let transfer_instruction = Transfer { @@ -158,7 +159,7 @@ impl TokenTransferExecutionContext for IbcStorage<'_, '_, '_> { let cpi_ctx = CpiContext::new_with_signer( token_program.clone(), transfer_instruction, - outer.as_slice(), //signer PDA + seeds, //signer PDA ); anchor_spl::token::transfer(cpi_ctx, amount_in_u64).unwrap(); @@ -181,9 +182,7 @@ impl TokenTransferExecutionContext for IbcStorage<'_, '_, '_> { let receiver_id = Pubkey::try_from(account) .map_err(|_| TokenTransferError::ParseAccountFailure)?; let base_denom = amt.denom.base_denom.to_string(); - let amount = amt.amount; - - let amount_in_u64 = check_amount_overflow(amount)?; + let amount_in_u64 = check_amount_overflow(amt.amount)?; let (token_mint_key, _bump) = Pubkey::find_program_address(&[base_denom.as_ref()], &crate::ID); @@ -231,8 +230,7 @@ impl TokenTransferExecutionContext for IbcStorage<'_, '_, '_> { let burner_id = Pubkey::try_from(account) .map_err(|_| TokenTransferError::ParseAccountFailure)?; let base_denom = amt.denom.base_denom.to_string(); - let amount = amt.amount; - let amount_in_u64 = check_amount_overflow(amount)?; + let amount_in_u64 = check_amount_overflow(amt.amount)?; let (token_mint_key, bump) = Pubkey::find_program_address(&[base_denom.as_ref()], &crate::ID); let (mint_authority_key, _bump) = From 2c565ca8093d8c1cd784bae132cfbd34abe51773 Mon Sep 17 00:00:00 2001 From: dhruvja Date: Mon, 27 Nov 2023 11:34:49 +0530 Subject: [PATCH 47/57] refactor send_coins_execute --- .../programs/solana-ibc/src/transfer/impls.rs | 77 ++++++------------- 1 file changed, 24 insertions(+), 53 deletions(-) diff --git a/solana/solana-ibc/programs/solana-ibc/src/transfer/impls.rs b/solana/solana-ibc/programs/solana-ibc/src/transfer/impls.rs index 3af764db..27e0cdc4 100644 --- a/solana/solana-ibc/programs/solana-ibc/src/transfer/impls.rs +++ b/solana/solana-ibc/programs/solana-ibc/src/transfer/impls.rs @@ -100,6 +100,8 @@ impl TokenTransferExecutionContext for IbcStorage<'_, '_, '_> { let (_token_mint_key, _bump) = Pubkey::find_program_address(&[base_denom.as_ref()], &crate::ID); + let (mint_authority_key, mint_authority_bump) = + Pubkey::find_program_address(&[MINT_ESCROW_SEED], &crate::ID); let store = self.borrow(); let accounts = &store.accounts; @@ -107,64 +109,33 @@ impl TokenTransferExecutionContext for IbcStorage<'_, '_, '_> { let receiver = get_account_info_from_key(accounts, receiver_id)?; let token_program = get_account_info_from_key(accounts, spl_token::ID)?; - if matches!(from, AccountId::Escrow(_)) { - let (mint_authority_key, mint_authority_bump) = - Pubkey::find_program_address(&[MINT_ESCROW_SEED], &crate::ID); - - let mint_authority = - get_account_info_from_key(accounts, mint_authority_key)?; - - let bump_vector = mint_authority_bump.to_le_bytes(); - let seeds = [MINT_ESCROW_SEED, bump_vector.as_ref()]; - let seeds = seeds.as_ref(); - let seeds = core::slice::from_ref(&seeds); - - // Below is the actual instruction that we are going to send to the Token program. - let transfer_instruction = Transfer { - from: sender.clone(), - to: receiver.clone(), - authority: mint_authority.clone(), - }; - let cpi_ctx = CpiContext::new_with_signer( - token_program.clone(), - transfer_instruction, - seeds, //signer PDA - ); - - anchor_spl::token::transfer(cpi_ctx, amount_in_u64).unwrap(); + let authority = if matches!(from, AccountId::Escrow(_)) { + get_account_info_from_key(accounts, mint_authority_key)? } else { let sender_token_account = TokenAccount::try_deserialize(&mut &sender.data.borrow()[..]) .unwrap(); - let sender_token_account_owner = sender_token_account.owner; - let authority = get_account_info_from_key( - accounts, - sender_token_account_owner, - )?; - - // PDA generated so that we can sign the tx - let (_mint_authority_key, mint_authority_bump) = - Pubkey::find_program_address(&[MINT_ESCROW_SEED], &crate::ID); - let bump_vector = mint_authority_bump.to_le_bytes(); - let seeds = [MINT_ESCROW_SEED, bump_vector.as_ref()]; - let seeds = seeds.as_ref(); - let seeds = core::slice::from_ref(&seeds); - - // Below is the actual instruction that we are going to send to the Token program. - let transfer_instruction = Transfer { - from: sender.clone(), - to: receiver.clone(), - authority: authority.clone(), - }; - let cpi_ctx = CpiContext::new_with_signer( - token_program.clone(), - transfer_instruction, - seeds, //signer PDA - ); - - anchor_spl::token::transfer(cpi_ctx, amount_in_u64).unwrap(); - } + get_account_info_from_key(accounts, sender_token_account.owner)? + }; + + let bump_vector = mint_authority_bump.to_le_bytes(); + let seeds = [MINT_ESCROW_SEED, bump_vector.as_ref()]; + let seeds = seeds.as_ref(); + let seeds = core::slice::from_ref(&seeds); + + // Below is the actual instruction that we are going to send to the Token program. + let transfer_instruction = Transfer { + from: sender.clone(), + to: receiver.clone(), + authority: authority.clone(), + }; + let cpi_ctx = CpiContext::new_with_signer( + token_program.clone(), + transfer_instruction, + seeds, //signer PDA + ); + anchor_spl::token::transfer(cpi_ctx, amount_in_u64).unwrap(); Ok(()) } From 6dffae9ecbf74af9ee6f19933ebafadde604cee5 Mon Sep 17 00:00:00 2001 From: dhruvja Date: Mon, 27 Nov 2023 11:36:48 +0530 Subject: [PATCH 48/57] use better method to get get client state in mocks --- solana/solana-ibc/programs/solana-ibc/src/mocks.rs | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/solana/solana-ibc/programs/solana-ibc/src/mocks.rs b/solana/solana-ibc/programs/solana-ibc/src/mocks.rs index ee3eb6bd..1671fec1 100644 --- a/solana/solana-ibc/programs/solana-ibc/src/mocks.rs +++ b/solana/solana-ibc/programs/solana-ibc/src/mocks.rs @@ -57,12 +57,7 @@ pub fn mock_deliver_impl( }); let any_client_state = store.client_state(&client_id).unwrap(); - let client_state: MockClientState = match any_client_state { - client_state::AnyClientState::Tendermint(_) => { - panic!("Only for mocks") - } - client_state::AnyClientState::Mock(mock) => mock, - }; + let client_state = MockClientState::try_from(any_client_state).unwrap(); // Store update time since its not called during mocks store From 84598578e96ac52be2f2b4bad6a79b0b0906a68b Mon Sep 17 00:00:00 2001 From: dhruvja Date: Mon, 27 Nov 2023 11:38:10 +0530 Subject: [PATCH 49/57] update cargo.toml --- solana/solana-ibc/programs/solana-ibc/Cargo.toml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/solana/solana-ibc/programs/solana-ibc/Cargo.toml b/solana/solana-ibc/programs/solana-ibc/Cargo.toml index cd638b78..cd561446 100644 --- a/solana/solana-ibc/programs/solana-ibc/Cargo.toml +++ b/solana/solana-ibc/programs/solana-ibc/Cargo.toml @@ -18,17 +18,17 @@ mocks = ["ibc/mocks", "ibc/std"] [dependencies] anchor-lang.workspace = true anchor-spl.workspace = true -uint.workspace = true base64.workspace = true bytemuck.workspace = true derive_more.workspace = true ibc-proto.workspace = true ibc.workspace = true +primitive-types.workspace = true serde.workspace = true serde_json.workspace = true -primitive-types.workspace = true -strum.workspace = true spl-associated-token-account.workspace = true +strum.workspace = true +uint.workspace = true blockchain.workspace = true lib.workspace = true From 4da027cb149c67b47a15deec68c77eba3b582820 Mon Sep 17 00:00:00 2001 From: dhruvja Date: Mon, 27 Nov 2023 11:52:09 +0530 Subject: [PATCH 50/57] fix clippy --- solana/solana-ibc/programs/solana-ibc/src/mocks.rs | 2 +- solana/solana-ibc/programs/solana-ibc/src/transfer/impls.rs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/solana/solana-ibc/programs/solana-ibc/src/mocks.rs b/solana/solana-ibc/programs/solana-ibc/src/mocks.rs index 1671fec1..8bfc6ef9 100644 --- a/solana/solana-ibc/programs/solana-ibc/src/mocks.rs +++ b/solana/solana-ibc/programs/solana-ibc/src/mocks.rs @@ -23,7 +23,7 @@ use ibc::mock::client_state::MockClientState; use storage::IbcPackets; use crate::{ - client_state, error, host, storage, MockDeliver, MINT_ESCROW_SEED, + error, host, storage, MockDeliver, MINT_ESCROW_SEED, }; pub fn mock_deliver_impl( diff --git a/solana/solana-ibc/programs/solana-ibc/src/transfer/impls.rs b/solana/solana-ibc/programs/solana-ibc/src/transfer/impls.rs index 27e0cdc4..3feddcb7 100644 --- a/solana/solana-ibc/programs/solana-ibc/src/transfer/impls.rs +++ b/solana/solana-ibc/programs/solana-ibc/src/transfer/impls.rs @@ -19,7 +19,7 @@ use crate::storage::IbcStorage; use crate::MINT_ESCROW_SEED; /// Structure to identify if the account is escrow or not. If it is escrow account, we derive the escrow account using port-id, channel-id and denom. -#[derive(Clone, Display, PartialEq, Eq, derive_more::From)] +#[derive(Clone, Display, PartialEq, Eq, derive_more::From, derive_more::TryInto)] pub enum AccountId { Signer(Pubkey), Escrow(PortChannelPK), @@ -29,7 +29,7 @@ impl TryFrom for AccountId { type Error = ::Err; fn try_from(value: ibc::Signer) -> Result { - Ok(Self::Signer(Pubkey::try_from(value.as_ref())?)) + Ok(Pubkey::try_from(value.as_ref()).map(Self::Signer).unwrap()) } } From 108802820d5cf9c05dc1f2ffdf54cce9fe33c0fb Mon Sep 17 00:00:00 2001 From: dhruvja Date: Mon, 27 Nov 2023 11:59:51 +0530 Subject: [PATCH 51/57] rm custom error and added try_into --- .../programs/solana-ibc/src/transfer/impls.rs | 22 +++++++------------ 1 file changed, 8 insertions(+), 14 deletions(-) diff --git a/solana/solana-ibc/programs/solana-ibc/src/transfer/impls.rs b/solana/solana-ibc/programs/solana-ibc/src/transfer/impls.rs index 3feddcb7..7e2ce538 100644 --- a/solana/solana-ibc/programs/solana-ibc/src/transfer/impls.rs +++ b/solana/solana-ibc/programs/solana-ibc/src/transfer/impls.rs @@ -33,21 +33,15 @@ impl TryFrom for AccountId { } } -#[derive(Debug)] -pub enum InvalidAccountIdVariant { - NotEscrowAccount, - NotSignerAccount, -} - impl AccountId { pub fn get_escrow_account( &self, denom: &str, - ) -> Result { + ) -> Result { let port_channel = match self { AccountId::Escrow(pk) => pk, AccountId::Signer(_) => { - return Err(InvalidAccountIdVariant::NotEscrowAccount) + return Err(()) } }; let channel_id = port_channel.channel_id(); @@ -61,13 +55,13 @@ impl AccountId { } impl TryFrom<&AccountId> for Pubkey { - type Error = InvalidAccountIdVariant; + type Error = (); fn try_from(value: &AccountId) -> Result { match value { AccountId::Signer(signer) => Ok(*signer), AccountId::Escrow(_) => { - Err(InvalidAccountIdVariant::NotSignerAccount) + Err(()) } } } @@ -89,10 +83,10 @@ impl TokenTransferExecutionContext for IbcStorage<'_, '_, '_> { amt.denom.base_denom ); let base_denom = amt.denom.base_denom.to_string(); - let sender_id = Pubkey::try_from(from).unwrap_or_else(|_| { + let sender_id = from.try_into().unwrap_or_else(|_| { from.get_escrow_account(base_denom.as_str()).unwrap() }); - let receiver_id = Pubkey::try_from(to).unwrap_or_else(|_| { + let receiver_id = to.try_into().unwrap_or_else(|_| { to.get_escrow_account(base_denom.as_str()).unwrap() }); @@ -150,7 +144,7 @@ impl TokenTransferExecutionContext for IbcStorage<'_, '_, '_> { amt.denom.trace_path, amt.denom.base_denom ); - let receiver_id = Pubkey::try_from(account) + let receiver_id = account.try_into() .map_err(|_| TokenTransferError::ParseAccountFailure)?; let base_denom = amt.denom.base_denom.to_string(); let amount_in_u64 = check_amount_overflow(amt.amount)?; @@ -198,7 +192,7 @@ impl TokenTransferExecutionContext for IbcStorage<'_, '_, '_> { amt.denom.trace_path, amt.denom.base_denom ); - let burner_id = Pubkey::try_from(account) + let burner_id = account.try_into() .map_err(|_| TokenTransferError::ParseAccountFailure)?; let base_denom = amt.denom.base_denom.to_string(); let amount_in_u64 = check_amount_overflow(amt.amount)?; From 69ee7f0751e3bdef311776a608510d2c2f3a44b4 Mon Sep 17 00:00:00 2001 From: dhruvja Date: Mon, 27 Nov 2023 12:00:11 +0530 Subject: [PATCH 52/57] fmt --- .../programs/solana-ibc/src/mocks.rs | 4 +--- .../programs/solana-ibc/src/transfer/impls.rs | 23 ++++++++----------- 2 files changed, 11 insertions(+), 16 deletions(-) diff --git a/solana/solana-ibc/programs/solana-ibc/src/mocks.rs b/solana/solana-ibc/programs/solana-ibc/src/mocks.rs index 8bfc6ef9..693c2cf5 100644 --- a/solana/solana-ibc/programs/solana-ibc/src/mocks.rs +++ b/solana/solana-ibc/programs/solana-ibc/src/mocks.rs @@ -22,9 +22,7 @@ use ibc::core::{ExecutionContext, ValidationContext}; use ibc::mock::client_state::MockClientState; use storage::IbcPackets; -use crate::{ - error, host, storage, MockDeliver, MINT_ESCROW_SEED, -}; +use crate::{error, host, storage, MockDeliver, MINT_ESCROW_SEED}; pub fn mock_deliver_impl( ctx: Context, diff --git a/solana/solana-ibc/programs/solana-ibc/src/transfer/impls.rs b/solana/solana-ibc/programs/solana-ibc/src/transfer/impls.rs index 7e2ce538..285018ae 100644 --- a/solana/solana-ibc/programs/solana-ibc/src/transfer/impls.rs +++ b/solana/solana-ibc/programs/solana-ibc/src/transfer/impls.rs @@ -19,7 +19,9 @@ use crate::storage::IbcStorage; use crate::MINT_ESCROW_SEED; /// Structure to identify if the account is escrow or not. If it is escrow account, we derive the escrow account using port-id, channel-id and denom. -#[derive(Clone, Display, PartialEq, Eq, derive_more::From, derive_more::TryInto)] +#[derive( + Clone, Display, PartialEq, Eq, derive_more::From, derive_more::TryInto, +)] pub enum AccountId { Signer(Pubkey), Escrow(PortChannelPK), @@ -34,15 +36,10 @@ impl TryFrom for AccountId { } impl AccountId { - pub fn get_escrow_account( - &self, - denom: &str, - ) -> Result { + pub fn get_escrow_account(&self, denom: &str) -> Result { let port_channel = match self { AccountId::Escrow(pk) => pk, - AccountId::Signer(_) => { - return Err(()) - } + AccountId::Signer(_) => return Err(()), }; let channel_id = port_channel.channel_id(); let port_id = port_channel.port_id(); @@ -60,9 +57,7 @@ impl TryFrom<&AccountId> for Pubkey { fn try_from(value: &AccountId) -> Result { match value { AccountId::Signer(signer) => Ok(*signer), - AccountId::Escrow(_) => { - Err(()) - } + AccountId::Escrow(_) => Err(()), } } } @@ -144,7 +139,8 @@ impl TokenTransferExecutionContext for IbcStorage<'_, '_, '_> { amt.denom.trace_path, amt.denom.base_denom ); - let receiver_id = account.try_into() + let receiver_id = account + .try_into() .map_err(|_| TokenTransferError::ParseAccountFailure)?; let base_denom = amt.denom.base_denom.to_string(); let amount_in_u64 = check_amount_overflow(amt.amount)?; @@ -192,7 +188,8 @@ impl TokenTransferExecutionContext for IbcStorage<'_, '_, '_> { amt.denom.trace_path, amt.denom.base_denom ); - let burner_id = account.try_into() + let burner_id = account + .try_into() .map_err(|_| TokenTransferError::ParseAccountFailure)?; let base_denom = amt.denom.base_denom.to_string(); let amount_in_u64 = check_amount_overflow(amt.amount)?; From 98e6fbd73b46cdf98aad77a33516f5f76da3def0 Mon Sep 17 00:00:00 2001 From: dhruvja Date: Mon, 27 Nov 2023 19:14:22 +0530 Subject: [PATCH 53/57] fix suggestions --- .../programs/solana-ibc/src/storage/ids.rs | 2 -- .../programs/solana-ibc/src/tests.rs | 7 +----- .../programs/solana-ibc/src/transfer/impls.rs | 24 ++++++++++--------- 3 files changed, 14 insertions(+), 19 deletions(-) diff --git a/solana/solana-ibc/programs/solana-ibc/src/storage/ids.rs b/solana/solana-ibc/programs/solana-ibc/src/storage/ids.rs index 3e0310d5..dd9ebe89 100644 --- a/solana/solana-ibc/programs/solana-ibc/src/storage/ids.rs +++ b/solana/solana-ibc/programs/solana-ibc/src/storage/ids.rs @@ -160,10 +160,8 @@ impl PortChannelPK { }) } - #[allow(dead_code)] pub fn port_id(&self) -> ibc::PortId { ibc::PortId::from(&self.port_key) } - #[allow(dead_code)] pub fn channel_id(&self) -> ibc::ChannelId { ibc::ChannelId::new(self.channel_idx.into()) } diff --git a/solana/solana-ibc/programs/solana-ibc/src/tests.rs b/solana/solana-ibc/programs/solana-ibc/src/tests.rs index b2655a79..62ea1af8 100644 --- a/solana/solana-ibc/programs/solana-ibc/src/tests.rs +++ b/solana/solana-ibc/programs/solana-ibc/src/tests.rs @@ -323,12 +323,7 @@ fn anchor_test_deliver() -> Result<()> { let mint_info = sol_rpc_client.get_token_supply(&token_mint_key).unwrap(); println!("This is the mint information {:?}", mint_info); - // Retrieve and validate state - // let solana_ibc_storage_account: PrivateStorage = - // program.account(storage).unwrap(); - - // println!("This is solana storage account {:?}", solana_ibc_storage_account); - + // Make sure all the accounts needed for transfer are ready ( mint, escrow etc.) // Pass the instruction for transfer diff --git a/solana/solana-ibc/programs/solana-ibc/src/transfer/impls.rs b/solana/solana-ibc/programs/solana-ibc/src/transfer/impls.rs index 285018ae..6b6e4cfa 100644 --- a/solana/solana-ibc/programs/solana-ibc/src/transfer/impls.rs +++ b/solana/solana-ibc/programs/solana-ibc/src/transfer/impls.rs @@ -77,12 +77,12 @@ impl TokenTransferExecutionContext for IbcStorage<'_, '_, '_> { amt.denom.trace_path, amt.denom.base_denom ); - let base_denom = amt.denom.base_denom.to_string(); + let base_denom = amt.denom.base_denom.as_str(); let sender_id = from.try_into().unwrap_or_else(|_| { - from.get_escrow_account(base_denom.as_str()).unwrap() + from.get_escrow_account(base_denom).unwrap() }); let receiver_id = to.try_into().unwrap_or_else(|_| { - to.get_escrow_account(base_denom.as_str()).unwrap() + to.get_escrow_account(base_denom).unwrap() }); let amount_in_u64 = check_amount_overflow(amt.amount)?; @@ -142,7 +142,7 @@ impl TokenTransferExecutionContext for IbcStorage<'_, '_, '_> { let receiver_id = account .try_into() .map_err(|_| TokenTransferError::ParseAccountFailure)?; - let base_denom = amt.denom.base_denom.to_string(); + let base_denom = amt.denom.base_denom.as_str(); let amount_in_u64 = check_amount_overflow(amt.amount)?; let (token_mint_key, _bump) = @@ -158,8 +158,9 @@ impl TokenTransferExecutionContext for IbcStorage<'_, '_, '_> { get_account_info_from_key(accounts, mint_authority_key)?; let bump_vector = mint_authority_bump.to_le_bytes(); - let inner = vec![MINT_ESCROW_SEED, bump_vector.as_ref()]; - let outer = vec![inner.as_slice()]; + let seeds = [MINT_ESCROW_SEED, bump_vector.as_ref()]; + let seeds = seeds.as_ref(); + let seeds = core::slice::from_ref(&seeds); // Below is the actual instruction that we are going to send to the Token program. let transfer_instruction = MintTo { @@ -170,7 +171,7 @@ impl TokenTransferExecutionContext for IbcStorage<'_, '_, '_> { let cpi_ctx = CpiContext::new_with_signer( token_program.clone(), transfer_instruction, - outer.as_slice(), //signer PDA + seeds, //signer PDA ); anchor_spl::token::mint_to(cpi_ctx, amount_in_u64).unwrap(); @@ -191,7 +192,7 @@ impl TokenTransferExecutionContext for IbcStorage<'_, '_, '_> { let burner_id = account .try_into() .map_err(|_| TokenTransferError::ParseAccountFailure)?; - let base_denom = amt.denom.base_denom.to_string(); + let base_denom = amt.denom.base_denom.as_str(); let amount_in_u64 = check_amount_overflow(amt.amount)?; let (token_mint_key, bump) = Pubkey::find_program_address(&[base_denom.as_ref()], &crate::ID); @@ -206,8 +207,9 @@ impl TokenTransferExecutionContext for IbcStorage<'_, '_, '_> { get_account_info_from_key(accounts, mint_authority_key)?; let bump_vector = bump.to_le_bytes(); - let inner = vec![base_denom.as_ref(), bump_vector.as_ref()]; - let outer = vec![inner.as_slice()]; + let seeds = [MINT_ESCROW_SEED, bump_vector.as_ref()]; + let seeds = seeds.as_ref(); + let seeds = core::slice::from_ref(&seeds); // Below is the actual instruction that we are going to send to the Token program. let transfer_instruction = Burn { @@ -218,7 +220,7 @@ impl TokenTransferExecutionContext for IbcStorage<'_, '_, '_> { let cpi_ctx = CpiContext::new_with_signer( token_program.clone(), transfer_instruction, - outer.as_slice(), //signer PDA + seeds, //signer PDA ); anchor_spl::token::burn(cpi_ctx, amount_in_u64).unwrap(); From d7ff0a321ff577545be30dc912bfd173d395e45c Mon Sep 17 00:00:00 2001 From: dhruvja Date: Mon, 27 Nov 2023 20:57:44 +0530 Subject: [PATCH 54/57] fix suggestions --- solana/solana-ibc/programs/solana-ibc/src/lib.rs | 1 - .../programs/solana-ibc/src/transfer/impls.rs | 10 +++++----- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/solana/solana-ibc/programs/solana-ibc/src/lib.rs b/solana/solana-ibc/programs/solana-ibc/src/lib.rs index d7ebde39..41f9cd52 100644 --- a/solana/solana-ibc/programs/solana-ibc/src/lib.rs +++ b/solana/solana-ibc/programs/solana-ibc/src/lib.rs @@ -169,7 +169,6 @@ pub mod solana_ibc { /// Called to set up a connection, channel and store the next /// sequence. Will panic if called without `mocks` feature. - #[allow(unused_variables)] pub fn mock_deliver( ctx: Context, port_id: PortId, diff --git a/solana/solana-ibc/programs/solana-ibc/src/transfer/impls.rs b/solana/solana-ibc/programs/solana-ibc/src/transfer/impls.rs index 6b6e4cfa..0fafb985 100644 --- a/solana/solana-ibc/programs/solana-ibc/src/transfer/impls.rs +++ b/solana/solana-ibc/programs/solana-ibc/src/transfer/impls.rs @@ -31,15 +31,15 @@ impl TryFrom for AccountId { type Error = ::Err; fn try_from(value: ibc::Signer) -> Result { - Ok(Pubkey::try_from(value.as_ref()).map(Self::Signer).unwrap()) + Pubkey::from_str(value.as_ref()).map(Self::Signer) } } impl AccountId { - pub fn get_escrow_account(&self, denom: &str) -> Result { + pub fn get_escrow_account(&self, denom: &str) -> Result { let port_channel = match self { AccountId::Escrow(pk) => pk, - AccountId::Signer(_) => return Err(()), + AccountId::Signer(_) => return Err("Expected Escrow account, instead found Signer account"), }; let channel_id = port_channel.channel_id(); let port_id = port_channel.port_id(); @@ -52,12 +52,12 @@ impl AccountId { } impl TryFrom<&AccountId> for Pubkey { - type Error = (); + type Error = >::Error; fn try_from(value: &AccountId) -> Result { match value { AccountId::Signer(signer) => Ok(*signer), - AccountId::Escrow(_) => Err(()), + AccountId::Escrow(_) => Err("Expected Signer account, instead found Escrow account"), } } } From 1d6f717141e3902b12cad46c45185f7a0699f041 Mon Sep 17 00:00:00 2001 From: dhruvja Date: Mon, 27 Nov 2023 20:58:43 +0530 Subject: [PATCH 55/57] fmt --- .../programs/solana-ibc/src/tests.rs | 2 +- .../programs/solana-ibc/src/transfer/impls.rs | 22 ++++++++++++------- 2 files changed, 15 insertions(+), 9 deletions(-) diff --git a/solana/solana-ibc/programs/solana-ibc/src/tests.rs b/solana/solana-ibc/programs/solana-ibc/src/tests.rs index 62ea1af8..1c6b4414 100644 --- a/solana/solana-ibc/programs/solana-ibc/src/tests.rs +++ b/solana/solana-ibc/programs/solana-ibc/src/tests.rs @@ -323,7 +323,7 @@ fn anchor_test_deliver() -> Result<()> { let mint_info = sol_rpc_client.get_token_supply(&token_mint_key).unwrap(); println!("This is the mint information {:?}", mint_info); - + // Make sure all the accounts needed for transfer are ready ( mint, escrow etc.) // Pass the instruction for transfer diff --git a/solana/solana-ibc/programs/solana-ibc/src/transfer/impls.rs b/solana/solana-ibc/programs/solana-ibc/src/transfer/impls.rs index 0fafb985..15169cbc 100644 --- a/solana/solana-ibc/programs/solana-ibc/src/transfer/impls.rs +++ b/solana/solana-ibc/programs/solana-ibc/src/transfer/impls.rs @@ -39,7 +39,11 @@ impl AccountId { pub fn get_escrow_account(&self, denom: &str) -> Result { let port_channel = match self { AccountId::Escrow(pk) => pk, - AccountId::Signer(_) => return Err("Expected Escrow account, instead found Signer account"), + AccountId::Signer(_) => { + return Err( + "Expected Escrow account, instead found Signer account" + ) + } }; let channel_id = port_channel.channel_id(); let port_id = port_channel.port_id(); @@ -57,7 +61,9 @@ impl TryFrom<&AccountId> for Pubkey { fn try_from(value: &AccountId) -> Result { match value { AccountId::Signer(signer) => Ok(*signer), - AccountId::Escrow(_) => Err("Expected Signer account, instead found Escrow account"), + AccountId::Escrow(_) => { + Err("Expected Signer account, instead found Escrow account") + } } } } @@ -78,12 +84,12 @@ impl TokenTransferExecutionContext for IbcStorage<'_, '_, '_> { amt.denom.base_denom ); let base_denom = amt.denom.base_denom.as_str(); - let sender_id = from.try_into().unwrap_or_else(|_| { - from.get_escrow_account(base_denom).unwrap() - }); - let receiver_id = to.try_into().unwrap_or_else(|_| { - to.get_escrow_account(base_denom).unwrap() - }); + let sender_id = from + .try_into() + .unwrap_or_else(|_| from.get_escrow_account(base_denom).unwrap()); + let receiver_id = to + .try_into() + .unwrap_or_else(|_| to.get_escrow_account(base_denom).unwrap()); let amount_in_u64 = check_amount_overflow(amt.amount)?; From 333776315cc4dffcf1398285b62fa8c87efacdb4 Mon Sep 17 00:00:00 2001 From: dhruvja Date: Mon, 27 Nov 2023 22:00:12 +0530 Subject: [PATCH 56/57] reduce unwraps --- .../programs/solana-ibc/src/transfer/impls.rs | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/solana/solana-ibc/programs/solana-ibc/src/transfer/impls.rs b/solana/solana-ibc/programs/solana-ibc/src/transfer/impls.rs index 15169cbc..e265624c 100644 --- a/solana/solana-ibc/programs/solana-ibc/src/transfer/impls.rs +++ b/solana/solana-ibc/programs/solana-ibc/src/transfer/impls.rs @@ -86,10 +86,12 @@ impl TokenTransferExecutionContext for IbcStorage<'_, '_, '_> { let base_denom = amt.denom.base_denom.as_str(); let sender_id = from .try_into() - .unwrap_or_else(|_| from.get_escrow_account(base_denom).unwrap()); + .or_else(|_| from.get_escrow_account(base_denom)) + .map_err(|_|TokenTransferError::ParseAccountFailure)?; let receiver_id = to .try_into() - .unwrap_or_else(|_| to.get_escrow_account(base_denom).unwrap()); + .or_else(|_| to.get_escrow_account(base_denom)) + .map_err(|_| TokenTransferError::ParseAccountFailure)?; let amount_in_u64 = check_amount_overflow(amt.amount)?; @@ -246,9 +248,8 @@ impl TokenTransferValidationContext for IbcStorage<'_, '_, '_> { port_id: &PortId, channel_id: &ChannelId, ) -> Result { - Ok(AccountId::Escrow( - PortChannelPK::try_from(port_id, channel_id).unwrap(), - )) + let port_channel = PortChannelPK::try_from(port_id, channel_id).map_err(|_| TokenTransferError::DestinationChannelNotFound { port_id: port_id.clone(), channel_id: channel_id.clone()})?; + Ok(AccountId::Escrow(port_channel)) } fn can_send_coins(&self) -> Result<(), TokenTransferError> { From ed1d8e67d858d88aa856a675ce55803a6882e682 Mon Sep 17 00:00:00 2001 From: dhruvja Date: Mon, 27 Nov 2023 22:43:11 +0530 Subject: [PATCH 57/57] fmt --- .../solana-ibc/programs/solana-ibc/src/transfer/impls.rs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/solana/solana-ibc/programs/solana-ibc/src/transfer/impls.rs b/solana/solana-ibc/programs/solana-ibc/src/transfer/impls.rs index e265624c..ea1e3c8a 100644 --- a/solana/solana-ibc/programs/solana-ibc/src/transfer/impls.rs +++ b/solana/solana-ibc/programs/solana-ibc/src/transfer/impls.rs @@ -87,7 +87,7 @@ impl TokenTransferExecutionContext for IbcStorage<'_, '_, '_> { let sender_id = from .try_into() .or_else(|_| from.get_escrow_account(base_denom)) - .map_err(|_|TokenTransferError::ParseAccountFailure)?; + .map_err(|_| TokenTransferError::ParseAccountFailure)?; let receiver_id = to .try_into() .or_else(|_| to.get_escrow_account(base_denom)) @@ -248,7 +248,11 @@ impl TokenTransferValidationContext for IbcStorage<'_, '_, '_> { port_id: &PortId, channel_id: &ChannelId, ) -> Result { - let port_channel = PortChannelPK::try_from(port_id, channel_id).map_err(|_| TokenTransferError::DestinationChannelNotFound { port_id: port_id.clone(), channel_id: channel_id.clone()})?; + let port_channel = PortChannelPK::try_from(port_id, channel_id) + .map_err(|_| TokenTransferError::DestinationChannelNotFound { + port_id: port_id.clone(), + channel_id: channel_id.clone(), + })?; Ok(AccountId::Escrow(port_channel)) }