From 1c9a658ee4104866a04f29b5c91b0047cf95b86d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Zemanovi=C4=8D?= Date: Thu, 18 Jul 2024 11:37:11 +0100 Subject: [PATCH] ibc: replace token dep with DI --- crates/benches/native_vps.rs | 26 ++++--- crates/ibc/Cargo.toml | 2 +- crates/ibc/src/actions.rs | 63 +++++++++++----- crates/ibc/src/context/common.rs | 13 ++-- crates/ibc/src/context/nft_transfer.rs | 33 ++++++--- crates/ibc/src/context/nft_transfer_mod.rs | 14 ++-- crates/ibc/src/context/token_transfer.rs | 2 +- crates/ibc/src/lib.rs | 64 +++++++++------- crates/ibc/src/msg.rs | 23 +++--- crates/ibc/src/storage.rs | 85 +++++++++++++--------- crates/ibc/src/vp/context.rs | 14 +--- crates/ibc/src/vp/mod.rs | 70 ++++++++++++++---- crates/node/src/bench_utils.rs | 4 +- crates/node/src/shell/finalize_block.rs | 9 ++- crates/node/src/shell/governance.rs | 9 ++- crates/sdk/src/masp.rs | 2 +- crates/sdk/src/validation.rs | 2 + crates/shielded_token/src/vp.rs | 20 +++-- crates/systems/src/ibc.rs | 5 +- crates/systems/src/trans_token.rs | 23 ++++++ crates/tests/src/vm_host_env/ibc.rs | 2 +- crates/tests/src/vm_host_env/mod.rs | 46 ++++++------ crates/trans_token/src/lib.rs | 55 ++++++++++++++ crates/tx_prelude/src/ibc.rs | 9 ++- wasm/Cargo.lock | 1 - wasm/tx_ibc/src/lib.rs | 5 +- wasm_for_tests/Cargo.lock | 1 - 27 files changed, 400 insertions(+), 202 deletions(-) diff --git a/crates/benches/native_vps.rs b/crates/benches/native_vps.rs index e045f0ba07..3ce7d57c63 100644 --- a/crates/benches/native_vps.rs +++ b/crates/benches/native_vps.rs @@ -1677,19 +1677,20 @@ fn ibc_vp_validate_action(c: &mut Criterion) { let exec_ctx = IbcVpContext::new(ibc.ctx.pre()); let ctx = Rc::new(RefCell::new(exec_ctx)); - let mut actions = IbcActions::<_, parameters::Store<_>>::new( - ctx.clone(), - verifiers.clone(), - ); + let mut actions = + IbcActions::<_, parameters::Store<_>, token::Store<()>>::new( + ctx.clone(), + verifiers.clone(), + ); actions.set_validation_params(ibc.validation_params().unwrap()); let module = TransferModule::new(ctx.clone(), verifiers); actions.add_transfer_module(module); - let module = NftTransferModule::new(ctx); + let module = NftTransferModule::<_, token::Store<()>>::new(ctx); actions.add_transfer_module(module); group.bench_function(bench_name, |b| { - b.iter(|| actions.validate(&tx_data).unwrap()) + b.iter(|| actions.validate::(&tx_data).unwrap()) }); } @@ -1737,19 +1738,20 @@ fn ibc_vp_execute_action(c: &mut Criterion) { let exec_ctx = IbcVpContext::new(ibc.ctx.pre()); let ctx = Rc::new(RefCell::new(exec_ctx)); - let mut actions = IbcActions::<_, parameters::Store<_>>::new( - ctx.clone(), - verifiers.clone(), - ); + let mut actions = + IbcActions::<_, parameters::Store<_>, token::Store<()>>::new( + ctx.clone(), + verifiers.clone(), + ); actions.set_validation_params(ibc.validation_params().unwrap()); let module = TransferModule::new(ctx.clone(), verifiers); actions.add_transfer_module(module); - let module = NftTransferModule::new(ctx); + let module = NftTransferModule::<_, token::Store<()>>::new(ctx); actions.add_transfer_module(module); group.bench_function(bench_name, |b| { - b.iter(|| actions.execute(&tx_data).unwrap()) + b.iter(|| actions.execute::(&tx_data).unwrap()) }); } diff --git a/crates/ibc/Cargo.toml b/crates/ibc/Cargo.toml index ad4690e419..53cd38d568 100644 --- a/crates/ibc/Cargo.toml +++ b/crates/ibc/Cargo.toml @@ -29,7 +29,6 @@ namada_migrations = {path = "../migrations", optional = true} namada_state = { path = "../state" } namada_storage = { path = "../storage" } namada_systems = { path = "../systems" } -namada_token = { path = "../token" } namada_tx = { path = "../tx" } namada_vp = { path = "../vp" } @@ -58,6 +57,7 @@ namada_governance = { path = "../governance" } namada_parameters = { path = "../parameters", features = ["testing"] } namada_proof_of_stake = { path = "../proof_of_stake", features = ["testing"] } namada_state = { path = "../state", features = ["testing"] } +namada_token = { path = "../token" } namada_tx = { path = "../tx", features = ["testing"] } namada_vm = { path = "../vm", features = ["testing"] } diff --git a/crates/ibc/src/actions.rs b/crates/ibc/src/actions.rs index 258627f195..e438eea3f2 100644 --- a/crates/ibc/src/actions.rs +++ b/crates/ibc/src/actions.rs @@ -2,14 +2,17 @@ use std::cell::RefCell; use std::collections::BTreeSet; +use std::fmt::Debug; +use std::marker::PhantomData; use std::rc::Rc; +use borsh::BorshDeserialize; use ibc::apps::transfer::types::msgs::transfer::MsgTransfer as IbcMsgTransfer; use ibc::apps::transfer::types::packet::PacketData; use ibc::apps::transfer::types::PrefixedCoin; use ibc::core::channel::types::timeout::TimeoutHeight; use namada_core::address::Address; -use namada_core::borsh::BorshSerializeExt; +use namada_core::borsh::{BorshSerialize, BorshSerializeExt}; use namada_core::ibc::PGFIbcTarget; use namada_core::tendermint::Time as TmTime; use namada_core::token::Amount; @@ -18,8 +21,7 @@ use namada_state::{ Epochs, ResultExt, State, StorageError, StorageRead, StorageResult, StorageWrite, }; -use namada_systems::parameters; -use namada_token as token; +use namada_systems::{parameters, trans_token}; use crate::event::IbcEvent; use crate::{ @@ -29,11 +31,13 @@ use crate::{ /// IBC protocol context #[derive(Debug)] -pub struct IbcProtocolContext<'a, S> { +pub struct IbcProtocolContext<'a, S, Token> { state: &'a mut S, + /// Marker for DI types + _marker: PhantomData, } -impl StorageRead for IbcProtocolContext<'_, S> +impl StorageRead for IbcProtocolContext<'_, S, Token> where S: State, { @@ -96,7 +100,7 @@ where } } -impl StorageWrite for IbcProtocolContext<'_, S> +impl StorageWrite for IbcProtocolContext<'_, S, Token> where S: State, { @@ -113,9 +117,13 @@ where } } -impl IbcStorageContext for IbcProtocolContext<'_, S> +impl IbcStorageContext for IbcProtocolContext<'_, S, Token> where S: State + EmitEvents, + Token: trans_token::Keys + + trans_token::Read + + trans_token::Write + + trans_token::Events, { type Storage = Self; @@ -141,7 +149,7 @@ where token: &Address, amount: Amount, ) -> Result<(), StorageError> { - token::transfer(self.state, token, src, dest, amount) + Token::transfer(self.state, token, src, dest, amount) } /// Mint token @@ -151,7 +159,9 @@ where token: &Address, amount: Amount, ) -> Result<(), StorageError> { - ibc_storage::mint_tokens(self.state, target, token, amount) + ibc_storage::mint_tokens_and_emit_event::<_, Token>( + self.state, target, token, amount, + ) } /// Burn token @@ -161,7 +171,7 @@ where token: &Address, amount: Amount, ) -> Result<(), StorageError> { - ibc_storage::burn_tokens(self.state, target, token, amount) + ibc_storage::burn_tokens::<_, Token>(self.state, target, token, amount) } fn insert_verifier( @@ -176,13 +186,18 @@ where } } -impl IbcCommonContext for IbcProtocolContext<'_, S> where - S: State + EmitEvents +impl IbcCommonContext for IbcProtocolContext<'_, S, Token> +where + S: State + EmitEvents, + Token: trans_token::Keys + + trans_token::Read + + trans_token::Write + + trans_token::Events, { } /// Transfer tokens over IBC -pub fn transfer_over_ibc<'a, S, Params>( +pub fn transfer_over_ibc<'a, S, Params, Token, Transfer>( state: &'a mut S, token: &Address, source: &Address, @@ -191,8 +206,13 @@ pub fn transfer_over_ibc<'a, S, Params>( where S: 'a + State + EmitEvents, Params: parameters::Read< - as IbcStorageContext>::Storage, + as IbcStorageContext>::Storage, >, + Token: trans_token::Keys + + trans_token::Write + + trans_token::Events + + Debug, + Transfer: BorshSerialize + BorshDeserialize, { let token = PrefixedCoin { denom: token.to_string().parse().expect("invalid token"), @@ -204,7 +224,10 @@ where receiver: target.target.clone().into(), memo: String::default().into(), }; - let ctx = IbcProtocolContext { state }; + let ctx = IbcProtocolContext { + state, + _marker: PhantomData, + }; let min_duration = Params::epoch_duration_parameter(&ctx)?.min_duration; #[allow(clippy::arithmetic_side_effects)] let timeout_timestamp = ctx @@ -224,7 +247,7 @@ where timeout_height_on_b: TimeoutHeight::Never, timeout_timestamp_on_b: timeout_timestamp.into(), }; - let data = MsgTransfer { + let data = MsgTransfer:: { message, transfer: None, } @@ -233,9 +256,11 @@ where // Use an empty verifiers set placeholder for validation, this is only // needed in txs and not protocol let verifiers = Rc::new(RefCell::new(BTreeSet::
::new())); - let mut actions = - IbcActions::<_, Params>::new(Rc::new(RefCell::new(ctx)), verifiers); - actions.execute(&data).into_storage_result()?; + let mut actions = IbcActions::<_, Params, Token>::new( + Rc::new(RefCell::new(ctx)), + verifiers, + ); + actions.execute::(&data).into_storage_result()?; Ok(()) } diff --git a/crates/ibc/src/context/common.rs b/crates/ibc/src/context/common.rs index 152653a797..659a7be072 100644 --- a/crates/ibc/src/context/common.rs +++ b/crates/ibc/src/context/common.rs @@ -22,9 +22,9 @@ use ibc::primitives::Timestamp; use namada_core::address::Address; use namada_core::storage::{BlockHeight, Key}; use namada_core::tendermint::Time as TmTime; +use namada_core::token::Amount; use namada_state::{StorageError, StorageRead, StorageWrite}; -use namada_token::storage_key::balance_key; -use namada_token::Amount; +use namada_systems::trans_token; use prost::Message; use super::client::{AnyClientState, AnyConsensusState}; @@ -689,14 +689,17 @@ pub trait IbcCommonContext: IbcStorageContext { } /// Return true if the NFT is owned by the owner - fn is_nft_owned( + fn is_nft_owned( &self, class_id: &PrefixedClassId, token_id: &TokenId, owner: &Address, - ) -> Result { + ) -> Result + where + Token: trans_token::Keys, + { let ibc_token = trace::ibc_token_for_nft(class_id, token_id); - let balance_key = balance_key(&ibc_token, owner); + let balance_key = Token::balance_key(&ibc_token, owner); let amount = self.storage().read::(&balance_key)?; Ok(amount == Some(Amount::from_u64(1))) } diff --git a/crates/ibc/src/context/nft_transfer.rs b/crates/ibc/src/context/nft_transfer.rs index e7317ba94e..a767834d80 100644 --- a/crates/ibc/src/context/nft_transfer.rs +++ b/crates/ibc/src/context/nft_transfer.rs @@ -1,6 +1,7 @@ //! IBC Non-Fungible token transfer context use std::cell::RefCell; +use std::marker::PhantomData; use std::rc::Rc; use ibc::apps::nft_transfer::context::{ @@ -15,26 +16,32 @@ use ibc::core::handler::types::error::ContextError; use ibc::core::host::types::identifiers::{ChannelId, PortId}; use namada_core::address::Address; use namada_core::token::Amount; +use namada_systems::trans_token; use super::common::IbcCommonContext; use crate::{trace, NftClass, NftMetadata, IBC_ESCROW_ADDRESS}; /// NFT transfer context to handle tokens #[derive(Debug)] -pub struct NftTransferContext +pub struct NftTransferContext where C: IbcCommonContext, { inner: Rc>, + _marker: PhantomData, } -impl NftTransferContext +impl NftTransferContext where C: IbcCommonContext, + Token: trans_token::Keys, { /// Make new NFT transfer context pub fn new(inner: Rc>) -> Self { - Self { inner } + Self { + inner, + _marker: PhantomData, + } } /// Update the mint amount of the token @@ -110,9 +117,10 @@ where } } -impl NftTransferValidationContext for NftTransferContext +impl NftTransferValidationContext for NftTransferContext where C: IbcCommonContext, + Token: trans_token::Keys, { type AccountId = Address; type Nft = NftMetadata; @@ -156,11 +164,11 @@ where self.get_nft(class_id, token_id)?; // Check the account owns the NFT - if self - .inner - .borrow() - .is_nft_owned(class_id, token_id, from_account)? - { + if self.inner.borrow().is_nft_owned::( + class_id, + token_id, + from_account, + )? { Ok(()) } else { Err(NftTransferError::Other(format!( @@ -183,7 +191,7 @@ where self.get_nft(class_id, token_id)?; // Check the NFT is escrowed - if self.inner.borrow().is_nft_owned( + if self.inner.borrow().is_nft_owned::( class_id, token_id, &IBC_ESCROW_ADDRESS, @@ -224,7 +232,7 @@ where if self .inner .borrow() - .is_nft_owned(class_id, token_id, account)? + .is_nft_owned::(class_id, token_id, account)? { Ok(()) } else { @@ -270,9 +278,10 @@ where } } -impl NftTransferExecutionContext for NftTransferContext +impl NftTransferExecutionContext for NftTransferContext where C: IbcCommonContext, + Token: trans_token::Keys, { fn create_or_update_class_execute( &self, diff --git a/crates/ibc/src/context/nft_transfer_mod.rs b/crates/ibc/src/context/nft_transfer_mod.rs index 1d94056425..420d80362e 100644 --- a/crates/ibc/src/context/nft_transfer_mod.rs +++ b/crates/ibc/src/context/nft_transfer_mod.rs @@ -27,6 +27,7 @@ use ibc::core::host::types::identifiers::{ChannelId, ConnectionId, PortId}; use ibc::core::router::module::Module; use ibc::core::router::types::module::{ModuleExtras, ModuleId}; use ibc::primitives::Signer; +use namada_systems::trans_token; use super::common::IbcCommonContext; use super::nft_transfer::NftTransferContext; @@ -34,17 +35,18 @@ use super::transfer_mod::ModuleWrapper; /// IBC module for NFT transfer #[derive(Debug)] -pub struct NftTransferModule +pub struct NftTransferModule where C: IbcCommonContext, { /// IBC actions - pub ctx: NftTransferContext, + pub ctx: NftTransferContext, } -impl NftTransferModule +impl NftTransferModule where C: IbcCommonContext, + Token: trans_token::Keys, { /// Make a new module pub fn new(ctx: Rc>) -> Self { @@ -54,9 +56,10 @@ where } } -impl ModuleWrapper for NftTransferModule +impl ModuleWrapper for NftTransferModule where C: IbcCommonContext + Debug, + Token: trans_token::Keys + Debug, { fn as_module(&self) -> &dyn Module { self @@ -75,9 +78,10 @@ where } } -impl Module for NftTransferModule +impl Module for NftTransferModule where C: IbcCommonContext + Debug, + Token: trans_token::Keys + Debug, { #[allow(clippy::too_many_arguments)] fn on_chan_open_init_validate( diff --git a/crates/ibc/src/context/token_transfer.rs b/crates/ibc/src/context/token_transfer.rs index 7d0ebee13e..ebfd0acd5b 100644 --- a/crates/ibc/src/context/token_transfer.rs +++ b/crates/ibc/src/context/token_transfer.rs @@ -13,8 +13,8 @@ use ibc::core::channel::types::error::ChannelError; use ibc::core::handler::types::error::ContextError; use ibc::core::host::types::identifiers::{ChannelId, PortId}; use namada_core::address::{Address, InternalAddress}; +use namada_core::token::Amount; use namada_core::uint::Uint; -use namada_token::Amount; use super::common::IbcCommonContext; use crate::{trace, IBC_ESCROW_ADDRESS}; diff --git a/crates/ibc/src/lib.rs b/crates/ibc/src/lib.rs index c5dbbfc2da..5c6544ac32 100644 --- a/crates/ibc/src/lib.rs +++ b/crates/ibc/src/lib.rs @@ -87,6 +87,7 @@ use namada_core::ibc::core::channel::types::commitment::{ compute_packet_commitment, AcknowledgementCommitment, PacketCommitment, }; use namada_core::masp::{addr_taddr, ibc_taddr, TAddrData}; +use namada_core::masp_primitives::transaction::components::ValueSum; use namada_core::token::Amount; use namada_events::EmitEvents; use namada_state::{ @@ -94,8 +95,7 @@ use namada_state::{ StorageWrite, WlState, DB, }; use namada_systems::ibc::ChangedBalances; -use namada_token::transaction::components::ValueSum; -use namada_token::Transfer; +use namada_systems::trans_token; pub use nft::*; use primitives::Timestamp; use prost::Message; @@ -216,11 +216,13 @@ impl namada_systems::ibc::Read for Store where S: StorageRead, { - fn try_extract_masp_tx_from_envelope( + fn try_extract_masp_tx_from_envelope( tx_data: &[u8], ) -> namada_storage::Result> { - let msg = decode_message(tx_data).into_storage_result().ok(); + let msg = decode_message::(tx_data) + .into_storage_result() + .ok(); let tx = if let Some(IbcMessage::Envelope(ref envelope)) = msg { Some(extract_masp_tx_from_envelope(envelope).ok_or_else(|| { namada_storage::Error::new_const( @@ -233,13 +235,15 @@ where Ok(tx) } - fn apply_ibc_packet( + fn apply_ibc_packet( storage: &S, tx_data: &[u8], mut acc: ChangedBalances, keys_changed: &BTreeSet, ) -> namada_storage::Result { - let msg = decode_message(tx_data).into_storage_result().ok(); + let msg = decode_message::(tx_data) + .into_storage_result() + .ok(); match msg { None => {} // This event is emitted on the sender @@ -533,19 +537,21 @@ where /// IBC actions to handle IBC operations #[derive(Debug)] -pub struct IbcActions<'a, C, Params> +pub struct IbcActions<'a, C, Params, Token> where C: IbcCommonContext, { ctx: IbcContext, router: IbcRouter<'a>, verifiers: Rc>>, + _marker: PhantomData, } -impl<'a, C, Params> IbcActions<'a, C, Params> +impl<'a, C, Params, Token> IbcActions<'a, C, Params, Token> where - C: IbcCommonContext + Debug, + C: IbcCommonContext, Params: namada_systems::parameters::Read, + Token: trans_token::Keys, { /// Make new IBC actions pub fn new( @@ -556,6 +562,7 @@ where ctx: IbcContext::new(ctx), router: IbcRouter::new(), verifiers, + _marker: PhantomData, } } @@ -570,12 +577,12 @@ where } /// Execute according to the message in an IBC transaction or VP - pub fn execute( + pub fn execute( &mut self, tx_data: &[u8], ) -> Result<(Option, Option), Error> { - let message = decode_message(tx_data)?; - match &message { + let message = decode_message::(tx_data)?; + match message { IbcMessage::Transfer(msg) => { let mut token_transfer_ctx = TokenTransferContext::new( self.ctx.inner.clone(), @@ -585,27 +592,27 @@ where send_transfer_execute( &mut self.ctx, &mut token_transfer_ctx, - msg.message.clone(), + msg.message, ) .map_err(Error::TokenTransfer)?; - Ok((msg.transfer.clone(), None)) + Ok((msg.transfer, None)) } IbcMessage::NftTransfer(msg) => { let mut nft_transfer_ctx = - NftTransferContext::new(self.ctx.inner.clone()); + NftTransferContext::<_, Token>::new(self.ctx.inner.clone()); send_nft_transfer_execute( &mut self.ctx, &mut nft_transfer_ctx, - msg.message.clone(), + msg.message, ) .map_err(Error::NftTransfer)?; - Ok((msg.transfer.clone(), None)) + Ok((msg.transfer, None)) } IbcMessage::Envelope(envelope) => { execute(&mut self.ctx, &mut self.router, *envelope.clone()) .map_err(|e| Error::Context(Box::new(e)))?; // Extract MASP tx from the memo in the packet if needed - let masp_tx = match &**envelope { + let masp_tx = match &*envelope { MsgEnvelope::Packet(packet_msg) => { match packet_msg { PacketMsg::Recv(msg) => { @@ -665,12 +672,15 @@ where } /// Validate according to the message in IBC VP - pub fn validate(&self, tx_data: &[u8]) -> Result<(), Error> { + pub fn validate( + &self, + tx_data: &[u8], + ) -> Result<(), Error> { // Use an empty verifiers set placeholder for validation, this is only // needed in actual txs to addresses whose VPs should be triggered let verifiers = Rc::new(RefCell::new(BTreeSet::
::new())); - let message = decode_message(tx_data)?; + let message = decode_message::(tx_data)?; match message { IbcMessage::Transfer(msg) => { let token_transfer_ctx = TokenTransferContext::new( @@ -687,7 +697,7 @@ where } IbcMessage::NftTransfer(msg) => { let nft_transfer_ctx = - NftTransferContext::new(self.ctx.inner.clone()); + NftTransferContext::<_, Token>::new(self.ctx.inner.clone()); send_nft_transfer_validate( &self.ctx, &nft_transfer_ctx, @@ -724,7 +734,9 @@ fn is_ack_successful(ack: &Acknowledgement) -> Result { } /// Tries to decode transaction data to an `IbcMessage` -pub fn decode_message(tx_data: &[u8]) -> Result { +pub fn decode_message( + tx_data: &[u8], +) -> Result, Error> { // ibc-rs message if let Ok(any_msg) = Any::decode(tx_data) { if let Ok(envelope) = MsgEnvelope::try_from(any_msg.clone()) { @@ -735,7 +747,7 @@ pub fn decode_message(tx_data: &[u8]) -> Result { message, transfer: None, }; - return Ok(IbcMessage::Transfer(msg)); + return Ok(IbcMessage::Transfer(Box::new(msg))); } if let Ok(message) = IbcMsgNftTransfer::try_from(any_msg) { let msg = MsgNftTransfer { @@ -747,12 +759,12 @@ pub fn decode_message(tx_data: &[u8]) -> Result { } // Transfer message with `ShieldingTransfer` - if let Ok(msg) = MsgTransfer::try_from_slice(tx_data) { - return Ok(IbcMessage::Transfer(msg)); + if let Ok(msg) = MsgTransfer::::try_from_slice(tx_data) { + return Ok(IbcMessage::Transfer(Box::new(msg))); } // NFT transfer message with `ShieldingTransfer` - if let Ok(msg) = MsgNftTransfer::try_from_slice(tx_data) { + if let Ok(msg) = MsgNftTransfer::::try_from_slice(tx_data) { return Ok(IbcMessage::NftTransfer(msg)); } diff --git a/crates/ibc/src/msg.rs b/crates/ibc/src/msg.rs index d3a32330f1..cf5c4a4d46 100644 --- a/crates/ibc/src/msg.rs +++ b/crates/ibc/src/msg.rs @@ -13,40 +13,39 @@ use ibc::core::host::types::identifiers::PortId; use ibc::primitives::proto::Protobuf; use masp_primitives::transaction::Transaction as MaspTransaction; use namada_core::borsh::BorshSerializeExt; -use namada_token::Transfer; /// The different variants of an Ibc message #[derive(Debug, Clone)] -pub enum IbcMessage { +pub enum IbcMessage { /// Ibc Envelop Envelope(Box), /// Ibc transaprent transfer - Transfer(MsgTransfer), + Transfer(Box>), /// NFT transfer - NftTransfer(MsgNftTransfer), + NftTransfer(MsgNftTransfer), } /// IBC transfer message with `Transfer` #[derive(Debug, Clone)] -pub struct MsgTransfer { +pub struct MsgTransfer { /// IBC transfer message pub message: IbcMsgTransfer, /// Shieleded transfer for MASP transaction pub transfer: Option, } -impl BorshSerialize for MsgTransfer { +impl BorshSerialize for MsgTransfer { fn serialize( &self, writer: &mut W, ) -> std::io::Result<()> { let encoded_msg = self.message.clone().encode_vec(); - let members = (encoded_msg, self.transfer.clone()); + let members = (encoded_msg, &self.transfer); BorshSerialize::serialize(&members, writer) } } -impl BorshDeserialize for MsgTransfer { +impl BorshDeserialize for MsgTransfer { fn deserialize_reader( reader: &mut R, ) -> std::io::Result { @@ -61,25 +60,25 @@ impl BorshDeserialize for MsgTransfer { /// IBC NFT transfer message with `Transfer` #[derive(Debug, Clone)] -pub struct MsgNftTransfer { +pub struct MsgNftTransfer { /// IBC NFT transfer message pub message: IbcMsgNftTransfer, /// Shieleded transfer for MASP transaction pub transfer: Option, } -impl BorshSerialize for MsgNftTransfer { +impl BorshSerialize for MsgNftTransfer { fn serialize( &self, writer: &mut W, ) -> std::io::Result<()> { let encoded_msg = self.message.clone().encode_vec(); - let members = (encoded_msg, self.transfer.clone()); + let members = (encoded_msg, &self.transfer); BorshSerialize::serialize(&members, writer) } } -impl BorshDeserialize for MsgNftTransfer { +impl BorshDeserialize for MsgNftTransfer { fn deserialize_reader( reader: &mut R, ) -> std::io::Result { diff --git a/crates/ibc/src/storage.rs b/crates/ibc/src/storage.rs index 1519a5f3e4..ff1056aab9 100644 --- a/crates/ibc/src/storage.rs +++ b/crates/ibc/src/storage.rs @@ -13,13 +13,12 @@ use ibc::core::host::types::path::{ ReceiptPath, SeqAckPath, SeqRecvPath, SeqSendPath, }; use namada_core::address::{Address, InternalAddress}; +use namada_core::borsh::BorshSerializeExt; use namada_core::storage::{DbKeySeg, Key, KeySeg}; use namada_core::token::Amount; -use namada_events::extend::UserAccount; -use namada_events::{EmitEvents, EventLevel}; +use namada_events::EmitEvents; use namada_state::{StorageRead, StorageResult, StorageWrite}; -use namada_token as token; -use namada_token::event::{TokenEvent, TokenOperation}; +use namada_systems::trans_token; use thiserror::Error; use crate::event::TOKEN_EVENT_DESCRIPTOR; @@ -54,60 +53,76 @@ pub enum Error { /// IBC storage functions result pub type Result = std::result::Result; +/// Mint IBC tokens. This function doesn't emit event (see +/// `mint_tokens_and_emit_event` below) +pub fn mint_tokens( + storage: &mut S, + target: &Address, + token: &Address, + amount: Amount, +) -> StorageResult<()> +where + S: StorageRead + StorageWrite, + Token: trans_token::Keys + trans_token::Read + trans_token::Write, +{ + Token::credit_tokens(storage, token, target, amount)?; + + let minter_key = Token::minter_key(token); + StorageWrite::write( + storage, + &minter_key, + Address::Internal(InternalAddress::Ibc).serialize_to_vec(), + ) +} + /// Mint tokens, and emit an IBC token mint event. -pub fn mint_tokens( - state: &mut S, +pub fn mint_tokens_and_emit_event( + storage: &mut S, target: &Address, token: &Address, amount: Amount, ) -> StorageResult<()> where S: StorageRead + StorageWrite + EmitEvents, + Token: trans_token::Keys + + trans_token::Read + + trans_token::Write + + trans_token::Events, { - token::mint_tokens( - state, - &Address::Internal(InternalAddress::Ibc), + mint_tokens::(storage, target, token, amount)?; + + Token::emit_mint_event( + storage, + TOKEN_EVENT_DESCRIPTOR.into(), token, - target, amount, + target, )?; - state.emit(TokenEvent { - descriptor: TOKEN_EVENT_DESCRIPTOR.into(), - level: EventLevel::Tx, - operation: TokenOperation::Mint { - token: token.clone(), - amount: amount.into(), - post_balance: token::read_balance(state, token, target)?.into(), - target_account: UserAccount::Internal(target.clone()), - }, - }); - Ok(()) } /// Burn tokens, and emit an IBC token burn event. -pub fn burn_tokens( - state: &mut S, +pub fn burn_tokens( + storage: &mut S, target: &Address, token: &Address, amount: Amount, ) -> StorageResult<()> where S: StorageRead + StorageWrite + EmitEvents, + Token: + trans_token::Read + trans_token::Write + trans_token::Events, { - token::burn_tokens(state, token, target, amount)?; - - state.emit(TokenEvent { - descriptor: TOKEN_EVENT_DESCRIPTOR.into(), - level: EventLevel::Tx, - operation: TokenOperation::Burn { - token: token.clone(), - amount: amount.into(), - post_balance: token::read_balance(state, token, target)?.into(), - target_account: UserAccount::Internal(target.clone()), - }, - }); + Token::burn_tokens(storage, token, target, amount)?; + + Token::emit_burn_event( + storage, + TOKEN_EVENT_DESCRIPTOR.into(), + token, + amount, + target, + )?; Ok(()) } diff --git a/crates/ibc/src/vp/context.rs b/crates/ibc/src/vp/context.rs index 38e57ff64a..822a951dc8 100644 --- a/crates/ibc/src/vp/context.rs +++ b/crates/ibc/src/vp/context.rs @@ -3,9 +3,8 @@ use std::collections::BTreeSet; use std::marker::PhantomData; -use namada_core::address::{Address, InternalAddress}; +use namada_core::address::Address; use namada_core::arith::checked; -use namada_core::borsh::BorshSerializeExt; use namada_core::collections::{HashMap, HashSet}; use namada_core::storage::{BlockHeight, Epoch, Epochs, Header, Key, TxIndex}; use namada_events::Event; @@ -20,7 +19,7 @@ use namada_vp::native_vp::{CtxPreStorageRead, VpEvaluator}; use namada_vp::VpEnv; use crate::event::IbcEvent; -use crate::storage::is_ibc_key; +use crate::storage::{self, is_ibc_key}; use crate::{IbcCommonContext, IbcStorageContext}; /// Pseudo execution environment context for ibc native vp @@ -247,14 +246,7 @@ where amount: Amount, ) -> Result<()> { let storage = self.storage_mut(); - Token::credit_tokens(storage, token, target, amount)?; - - let minter_key = Token::minter_key(token); - StorageWrite::write( - storage, - &minter_key, - Address::Internal(InternalAddress::Ibc).serialize_to_vec(), - ) + storage::mint_tokens::<_, Token>(storage, target, token, amount) } fn burn_token( diff --git a/crates/ibc/src/vp/mod.rs b/crates/ibc/src/vp/mod.rs index e2099d4e43..ab3da93b1a 100644 --- a/crates/ibc/src/vp/mod.rs +++ b/crates/ibc/src/vp/mod.rs @@ -9,6 +9,7 @@ use std::marker::PhantomData; use std::rc::Rc; use std::time::Duration; +use borsh::BorshDeserialize; use context::{ PseudoExecutionContext, PseudoExecutionStorage, VpValidationContext, }; @@ -78,6 +79,7 @@ pub struct Ibc< Gov, Token, PoS, + Transfer, > where S: 'static + StateRead, EVAL: VpEvaluator<'ctx, S, CA, EVAL>, @@ -85,8 +87,15 @@ pub struct Ibc< /// Context to interact with the host structures. pub ctx: Ctx<'ctx, S, CA, EVAL>, /// Generic types for DI - pub _marker: - PhantomData<(Params, ParamsPre, ParamsPseudo, Gov, Token, PoS)>, + pub _marker: PhantomData<( + Params, + ParamsPre, + ParamsPseudo, + Gov, + Token, + PoS, + Transfer, + )>, } impl< @@ -101,8 +110,21 @@ impl< Gov, Token, PoS, + Transfer, > NativeVp<'view> - for Ibc<'ctx, S, CA, EVAL, Params, ParamsPre, ParamsPseudo, Gov, Token, PoS> + for Ibc< + 'ctx, + S, + CA, + EVAL, + Params, + ParamsPre, + ParamsPseudo, + Gov, + Token, + PoS, + Transfer, + > where S: 'static + StateRead, EVAL: 'static + VpEvaluator<'ctx, S, CA, EVAL> + Debug, @@ -117,6 +139,7 @@ where + token::Write> + Debug, PoS: proof_of_stake::Read>, + Transfer: BorshDeserialize, { type Error = Error; @@ -171,7 +194,21 @@ impl< Gov, Token, PoS, -> Ibc<'ctx, S, CA, EVAL, Params, ParamsPre, ParamsPseudo, Gov, Token, PoS> + Transfer, +> + Ibc< + 'ctx, + S, + CA, + EVAL, + Params, + ParamsPre, + ParamsPseudo, + Gov, + Token, + PoS, + Transfer, + > where S: 'static + StateRead, EVAL: 'static + VpEvaluator<'ctx, S, CA, EVAL> + Debug, @@ -185,6 +222,7 @@ where + token::Write> + Debug, PoS: proof_of_stake::Read>, + Transfer: BorshDeserialize, { /// Instantiate IBC VP pub fn new(ctx: Ctx<'ctx, S, CA, EVAL>) -> Self { @@ -208,17 +246,19 @@ where // needed in actual txs to addresses whose VPs should be triggered let verifiers = Rc::new(RefCell::new(BTreeSet::
::new())); - let mut actions = - IbcActions::<_, ParamsPseudo>::new(ctx.clone(), verifiers.clone()); + let mut actions = IbcActions::<_, ParamsPseudo, Token>::new( + ctx.clone(), + verifiers.clone(), + ); let module = TransferModule::new(ctx.clone(), verifiers); actions.add_transfer_module(module); - let module = NftTransferModule::new(ctx.clone()); + let module = NftTransferModule::<_, Token>::new(ctx.clone()); actions.add_transfer_module(module); // Charge gas for the expensive execution self.ctx .charge_gas(IBC_ACTION_EXECUTE_GAS) .map_err(Error::NativeVpError)?; - actions.execute(tx_data)?; + actions.execute::(tx_data)?; let changed_ibc_keys: HashSet<&Key> = keys_changed.iter().filter(|k| is_ibc_key(k)).collect(); @@ -265,18 +305,20 @@ where let verifiers = Rc::new(RefCell::new(BTreeSet::
::new())); let mut actions = - IbcActions::<_, Params>::new(ctx.clone(), verifiers.clone()); + IbcActions::<_, Params, Token>::new(ctx.clone(), verifiers.clone()); actions.set_validation_params(self.validation_params()?); let module = TransferModule::new(ctx.clone(), verifiers); actions.add_transfer_module(module); - let module = NftTransferModule::new(ctx); + let module = NftTransferModule::<_, Token>::new(ctx); actions.add_transfer_module(module); // Charge gas for the expensive validation self.ctx .charge_gas(IBC_ACTION_VALIDATE_GAS) .map_err(Error::NativeVpError)?; - actions.validate(tx_data).map_err(Error::IbcAction) + actions + .validate::(tx_data) + .map_err(Error::IbcAction) } /// Retrieve the validation params @@ -457,6 +499,7 @@ mod tests { use namada_state::testing::TestState; use namada_state::StorageRead; use namada_token::storage_key::balance_key; + use namada_token::Transfer; use namada_tx::data::TxType; use namada_tx::{Authorization, Code, Data, Section, Tx}; use namada_vm::wasm::run::VpEvalWasm; @@ -579,6 +622,7 @@ mod tests { namada_proof_of_stake::Store< CtxPreStorageRead<'ctx, 'ctx, TestState, VpCache, Eval>, >, + Transfer, >; const ADDRESS: Address = Address::Internal(InternalAddress::Ibc); @@ -2322,7 +2366,7 @@ mod tests { let tx_index = TxIndex::default(); let tx_code = vec![]; - let tx_data = MsgTransfer { + let tx_data = MsgTransfer:: { message: msg, transfer: None, } @@ -3181,7 +3225,7 @@ mod tests { let tx_index = TxIndex::default(); let tx_code = vec![]; - let tx_data = MsgNftTransfer { + let tx_data = MsgNftTransfer:: { message: msg, transfer: None, } diff --git a/crates/node/src/bench_utils.rs b/crates/node/src/bench_utils.rs index d0811a3897..60c0d3bf91 100644 --- a/crates/node/src/bench_utils.rs +++ b/crates/node/src/bench_utils.rs @@ -396,7 +396,7 @@ impl BenchShell { timeout_timestamp_on_b: timeout_timestamp, }; - let msg = MsgTransfer { + let msg = MsgTransfer:: { message, transfer: None, }; @@ -1260,7 +1260,7 @@ impl BenchShieldedCtx { .get_masp_section(&transfer.shielded_section_hash.unwrap()) .unwrap() .clone(); - let msg = MsgTransfer { + let msg = MsgTransfer:: { message: msg, transfer: Some(transfer), }; diff --git a/crates/node/src/shell/finalize_block.rs b/crates/node/src/shell/finalize_block.rs index b0124d9395..e29b52389b 100644 --- a/crates/node/src/shell/finalize_block.rs +++ b/crates/node/src/shell/finalize_block.rs @@ -1186,9 +1186,12 @@ where pgf_inflation::apply_inflation::<_, parameters::Store<_>, token::Store<_>, _>( storage, |state, token, source, target| { - ibc::transfer_over_ibc::<_, parameters::Store<_>>( - state, token, source, target, - ) + ibc::transfer_over_ibc::< + _, + parameters::Store<_>, + token::Store<_>, + token::Transfer, + >(state, token, source, target) }, ) } diff --git a/crates/node/src/shell/governance.rs b/crates/node/src/shell/governance.rs index 6d5508f7d0..47c8de500b 100644 --- a/crates/node/src/shell/governance.rs +++ b/crates/node/src/shell/governance.rs @@ -575,8 +575,13 @@ where }, ), PGFTarget::Ibc(target) => ( - ibc::transfer_over_ibc::<_, parameters::Store<_>>( - state, token, &ADDRESS, target, + ibc::transfer_over_ibc::< + _, + parameters::Store<_>, + token::Store<_>, + token::Transfer, + >( + state, token, &ADDRESS, target ), TokenEvent { descriptor: "pgf-payments-over-ibc".into(), diff --git a/crates/sdk/src/masp.rs b/crates/sdk/src/masp.rs index edd5888601..2779e9ce08 100644 --- a/crates/sdk/src/masp.rs +++ b/crates/sdk/src/masp.rs @@ -711,7 +711,7 @@ impl ShieldedContext { let tx_data = tx.data(cmt).ok_or_else(|| { Error::Other("Missing transaction data".to_string()) })?; - let ibc_msg = decode_message(&tx_data) + let ibc_msg = decode_message::(&tx_data) .map_err(|_| Error::Other("Invalid IBC message".to_string()))?; if let IbcMessage::Envelope(ref envelope) = ibc_msg { if let Some(masp_tx) = extract_masp_tx_from_envelope(envelope) { diff --git a/crates/sdk/src/validation.rs b/crates/sdk/src/validation.rs index 952bd56a79..c1c8d8ab13 100644 --- a/crates/sdk/src/validation.rs +++ b/crates/sdk/src/validation.rs @@ -36,6 +36,7 @@ pub type IbcVp<'a, S, CA> = ibc::vp::Ibc< GovPreStore<'a, S, CA>, TokenStoreForIbcExec<'a, S, CA>, PosPreStore<'a, S, CA>, + token::Transfer, >; /// IBC VP pseudo-execution context @@ -92,6 +93,7 @@ pub type MaspVp<'a, S, CA> = token::vp::MaspVp< GovPreStore<'a, S, CA>, IbcPostStore<'a, S, CA>, TokenPreStore<'a, S, CA>, + token::Transfer, >; /// Native ETH bridge VP diff --git a/crates/shielded_token/src/vp.rs b/crates/shielded_token/src/vp.rs index 85f3b86840..b0fe05b27f 100644 --- a/crates/shielded_token/src/vp.rs +++ b/crates/shielded_token/src/vp.rs @@ -4,6 +4,7 @@ use std::cmp::Ordering; use std::collections::{BTreeMap, BTreeSet}; use std::marker::PhantomData; +use borsh::BorshDeserialize; use masp_primitives::asset_type::AssetType; use masp_primitives::merkle_tree::CommitmentTree; use masp_primitives::sapling::Node; @@ -49,7 +50,7 @@ pub enum Error { pub type Result = std::result::Result; /// MASP VP -pub struct MaspVp<'ctx, S, CA, EVAL, Params, Gov, Ibc, TransToken> +pub struct MaspVp<'ctx, S, CA, EVAL, Params, Gov, Ibc, TransToken, Transfer> where S: 'static + StateRead, EVAL: VpEvaluator<'ctx, S, CA, EVAL>, @@ -57,7 +58,7 @@ where /// Context to interact with the host structures. pub ctx: Ctx<'ctx, S, CA, EVAL>, /// Generic types for DI - pub _marker: PhantomData<(Params, Gov, Ibc, TransToken)>, + pub _marker: PhantomData<(Params, Gov, Ibc, TransToken, Transfer)>, } // The balances changed by the transaction, split between masp and non-masp @@ -73,8 +74,8 @@ struct ChangedBalances { post: BTreeMap>, } -impl<'view, 'ctx: 'view, S, CA, EVAL, Params, Gov, Ibc, TransToken> - MaspVp<'ctx, S, CA, EVAL, Params, Gov, Ibc, TransToken> +impl<'view, 'ctx: 'view, S, CA, EVAL, Params, Gov, Ibc, TransToken, Transfer> + MaspVp<'ctx, S, CA, EVAL, Params, Gov, Ibc, TransToken, Transfer> where S: 'static + StateRead, CA: 'static + Clone, @@ -84,6 +85,7 @@ where Ibc: ibc::Read>, TransToken: trans_token::Keys + trans_token::Read>, + Transfer: BorshDeserialize, { /// Instantiate MASP VP pub fn new(ctx: Ctx<'ctx, S, CA, EVAL>) -> Self { @@ -380,7 +382,7 @@ where post, } = changed_balances; let ibc::ChangedBalances { decoder, pre, post } = - Ibc::apply_ibc_packet( + Ibc::apply_ibc_packet::( &self.ctx.post(), tx_data, ibc::ChangedBalances { decoder, pre, post }, @@ -415,7 +417,7 @@ where .data(batched_tx.cmt) .ok_or_err_msg("No transaction data")?; let shielded_tx = if let Some(tx) = - Ibc::try_extract_masp_tx_from_envelope(&tx_data)? + Ibc::try_extract_masp_tx_from_envelope::(&tx_data)? { tx } else { @@ -882,8 +884,9 @@ fn verify_sapling_balancing_value( } } -impl<'view, 'ctx: 'view, S, CA, EVAL, Params, Gov, Ibc, TransToken> - NativeVp<'view> for MaspVp<'ctx, S, CA, EVAL, Params, Gov, Ibc, TransToken> +impl<'view, 'ctx: 'view, S, CA, EVAL, Params, Gov, Ibc, TransToken, Transfer> + NativeVp<'view> + for MaspVp<'ctx, S, CA, EVAL, Params, Gov, Ibc, TransToken, Transfer> where S: 'static + StateRead, CA: 'static + Clone, @@ -893,6 +896,7 @@ where Ibc: ibc::Read>, TransToken: trans_token::Keys + trans_token::Read>, + Transfer: BorshDeserialize, { type Error = Error; diff --git a/crates/systems/src/ibc.rs b/crates/systems/src/ibc.rs index 970ceac999..549865104e 100644 --- a/crates/systems/src/ibc.rs +++ b/crates/systems/src/ibc.rs @@ -5,6 +5,7 @@ use std::collections::{BTreeMap, BTreeSet}; use masp_primitives::transaction::components::ValueSum; use masp_primitives::transaction::TransparentAddress; use namada_core::address::Address; +use namada_core::borsh::BorshDeserialize; use namada_core::masp::TAddrData; use namada_core::{masp_primitives, storage, token}; pub use namada_storage::Result; @@ -12,12 +13,12 @@ pub use namada_storage::Result; /// Abstract IBC storage read interface pub trait Read { /// Extract MASP transaction from IBC envelope - fn try_extract_masp_tx_from_envelope( + fn try_extract_masp_tx_from_envelope( tx_data: &[u8], ) -> Result>; /// Apply relevant IBC packets to the changed balances structure - fn apply_ibc_packet( + fn apply_ibc_packet( storage: &S, tx_data: &[u8], acc: ChangedBalances, diff --git a/crates/systems/src/trans_token.rs b/crates/systems/src/trans_token.rs index 7793e6046d..16440d3f2f 100644 --- a/crates/systems/src/trans_token.rs +++ b/crates/systems/src/trans_token.rs @@ -1,5 +1,7 @@ //! Transparent token abstract interfaces +use std::borrow::Cow; + use namada_core::address::Address; pub use namada_core::token::*; use namada_core::{storage, token}; @@ -89,3 +91,24 @@ pub trait Write: Read { amount: token::Amount, ) -> Result<()>; } + +/// Abstract token events interface +pub trait Events: Read { + /// Emit mint token event + fn emit_mint_event( + storage: &mut S, + descriptor: Cow<'static, str>, + token: &Address, + amount: token::Amount, + target: &Address, + ) -> Result<()>; + + /// Emit burn token event + fn emit_burn_event( + storage: &mut S, + descriptor: Cow<'static, str>, + token: &Address, + amount: token::Amount, + target: &Address, + ) -> Result<()>; +} diff --git a/crates/tests/src/vm_host_env/ibc.rs b/crates/tests/src/vm_host_env/ibc.rs index 7b3fae4673..45fddb5f83 100644 --- a/crates/tests/src/vm_host_env/ibc.rs +++ b/crates/tests/src/vm_host_env/ibc.rs @@ -612,7 +612,7 @@ pub fn msg_transfer( channel_id: ChannelId, denom: String, sender: &Address, -) -> MsgTransfer { +) -> MsgTransfer { let timestamp = (Timestamp::now() + Duration::from_secs(100)).unwrap(); let message = IbcMsgTransfer { port_id_on_a: port_id, diff --git a/crates/tests/src/vm_host_env/mod.rs b/crates/tests/src/vm_host_env/mod.rs index 290b4a65af..2dd015cc07 100644 --- a/crates/tests/src/vm_host_env/mod.rs +++ b/crates/tests/src/vm_host_env/mod.rs @@ -698,7 +698,7 @@ mod tests { // create a client with the message tx_host_env::ibc::ibc_actions(tx::ctx()) - .execute(&tx_data) + .execute::(&tx_data) .expect("creating a client failed"); // Check @@ -731,7 +731,7 @@ mod tests { .sign_wrapper(keypair); // update the client with the message tx_host_env::ibc::ibc_actions(tx::ctx()) - .execute(&tx_data) + .execute::(&tx_data) .expect("updating a client failed"); // Check @@ -774,7 +774,7 @@ mod tests { .sign_wrapper(keypair.clone()); // init a connection with the message tx_host_env::ibc::ibc_actions(tx::ctx()) - .execute(&tx_data) + .execute::(&tx_data) .expect("creating a connection failed"); // Check @@ -807,7 +807,7 @@ mod tests { .sign_wrapper(keypair); // open the connection with the message tx_host_env::ibc::ibc_actions(tx::ctx()) - .execute(&tx_data) + .execute::(&tx_data) .expect("opening the connection failed"); // Check @@ -851,7 +851,7 @@ mod tests { .sign_wrapper(keypair.clone()); // open try a connection with the message tx_host_env::ibc::ibc_actions(tx::ctx()) - .execute(&tx_data) + .execute::(&tx_data) .expect("creating a connection failed"); // Check @@ -884,7 +884,7 @@ mod tests { .sign_wrapper(keypair); // open the connection with the mssage tx_host_env::ibc::ibc_actions(tx::ctx()) - .execute(&tx_data) + .execute::(&tx_data) .expect("opening the connection failed"); // Check @@ -930,7 +930,7 @@ mod tests { .sign_wrapper(keypair.clone()); // init a channel with the message tx_host_env::ibc::ibc_actions(tx::ctx()) - .execute(&tx_data) + .execute::(&tx_data) .expect("creating a channel failed"); // Check @@ -963,7 +963,7 @@ mod tests { .sign_wrapper(keypair); // open the channel with the message tx_host_env::ibc::ibc_actions(tx::ctx()) - .execute(&tx_data) + .execute::(&tx_data) .expect("opening the channel failed"); // Check @@ -1009,7 +1009,7 @@ mod tests { .sign_wrapper(keypair.clone()); // try open a channel with the message tx_host_env::ibc::ibc_actions(tx::ctx()) - .execute(&tx_data) + .execute::(&tx_data) .expect("creating a channel failed"); // Check @@ -1043,7 +1043,7 @@ mod tests { .sign_wrapper(keypair); // open a channel with the message tx_host_env::ibc::ibc_actions(tx::ctx()) - .execute(&tx_data) + .execute::(&tx_data) .expect("opening the channel failed"); // Check @@ -1098,7 +1098,7 @@ mod tests { let dummy_module = DummyNftTransferModule {}; actions.add_transfer_module(dummy_module); actions - .execute(&tx_data) + .execute::(&tx_data) .expect("closing the channel failed"); // Check @@ -1152,7 +1152,7 @@ mod tests { // close the channel with the message tx_host_env::ibc::ibc_actions(tx::ctx()) - .execute(&tx_data) + .execute::(&tx_data) .expect("closing the channel failed"); // Check @@ -1201,7 +1201,7 @@ mod tests { .sign_wrapper(keypair.clone()); // send the token and a packet with the data tx_host_env::ibc::ibc_actions(tx::ctx()) - .execute(&tx_data) + .execute::(&tx_data) .expect("sending a token failed"); // Check @@ -1251,7 +1251,7 @@ mod tests { .sign_wrapper(keypair); // ack the packet with the message tx_host_env::ibc::ibc_actions(tx::ctx()) - .execute(&tx_data) + .execute::(&tx_data) .expect("ack failed"); // Check @@ -1338,7 +1338,7 @@ mod tests { .sign_wrapper(keypair); // send the token and a packet with the data tx_host_env::ibc::ibc_actions(tx::ctx()) - .execute(&tx_data) + .execute::(&tx_data) .expect("sending a token failed"); // Check @@ -1422,7 +1422,7 @@ mod tests { .sign_wrapper(keypair); // receive a packet with the message tx_host_env::ibc::ibc_actions(tx::ctx()) - .execute(&tx_data) + .execute::(&tx_data) .expect("receiving the token failed"); // Check @@ -1517,7 +1517,7 @@ mod tests { .sign_wrapper(keypair); // Receive the packet, but no token is received tx_host_env::ibc::ibc_actions(tx::ctx()) - .execute(&tx_data) + .execute::(&tx_data) .expect("receiving the token failed"); // Check if the transaction is valid @@ -1612,7 +1612,7 @@ mod tests { .sign_wrapper(keypair); // receive a packet with the message tx_host_env::ibc::ibc_actions(tx::ctx()) - .execute(&tx_data) + .execute::(&tx_data) .expect("receiving a token failed"); // Check @@ -1716,7 +1716,7 @@ mod tests { .sign_wrapper(keypair); // receive a packet with the message tx_host_env::ibc::ibc_actions(tx::ctx()) - .execute(&tx_data) + .execute::(&tx_data) .expect("receiving a token failed"); // Check @@ -1780,7 +1780,7 @@ mod tests { let tx_data = msg.serialize_to_vec(); // send a packet with the message tx_host_env::ibc::ibc_actions(tx::ctx()) - .execute(&tx_data) + .execute::(&tx_data) .expect("sending a token failed"); // Commit @@ -1812,7 +1812,7 @@ mod tests { // timeout the packet tx_host_env::ibc::ibc_actions(tx::ctx()) - .execute(&tx_data) + .execute::(&tx_data) .expect("timeout failed"); // Check @@ -1866,7 +1866,7 @@ mod tests { let tx_data = msg.serialize_to_vec(); // send a packet with the message tx_host_env::ibc::ibc_actions(tx::ctx()) - .execute(&tx_data) + .execute::(&tx_data) .expect("sending a token failed"); // Commit @@ -1898,7 +1898,7 @@ mod tests { // timeout the packet tx_host_env::ibc::ibc_actions(tx::ctx()) - .execute(&tx_data) + .execute::(&tx_data) .expect("timeout on close failed"); // Check diff --git a/crates/trans_token/src/lib.rs b/crates/trans_token/src/lib.rs index b9cc0bdea7..024004972a 100644 --- a/crates/trans_token/src/lib.rs +++ b/crates/trans_token/src/lib.rs @@ -24,8 +24,12 @@ pub mod vp; use std::marker::PhantomData; +use event::{TokenEvent, TokenOperation}; use namada_core::address::Address; use namada_core::token; +use namada_core::uint::Uint; +use namada_events::extend::UserAccount; +use namada_events::{EmitEvents, EventLevel}; use namada_storage::{StorageRead, StorageWrite}; pub use namada_systems::trans_token::*; pub use storage::*; @@ -125,3 +129,54 @@ where storage::credit_tokens(storage, token, dest, amount) } } + +impl Events for Store +where + S: StorageRead + EmitEvents, +{ + fn emit_mint_event( + storage: &mut S, + descriptor: std::borrow::Cow<'static, str>, + token: &Address, + amount: token::Amount, + target: &Address, + ) -> Result<()> { + let post_balance: Uint = + Self::read_balance(storage, token, target)?.into(); + + storage.emit(TokenEvent { + descriptor, + level: EventLevel::Tx, + operation: TokenOperation::Mint { + token: token.clone(), + amount: amount.into(), + post_balance, + target_account: UserAccount::Internal(target.clone()), + }, + }); + Ok(()) + } + + fn emit_burn_event( + storage: &mut S, + descriptor: std::borrow::Cow<'static, str>, + token: &Address, + amount: token::Amount, + target: &Address, + ) -> Result<()> { + let post_balance: Uint = + Self::read_balance(storage, token, target)?.into(); + + storage.emit(TokenEvent { + descriptor, + level: EventLevel::Tx, + operation: TokenOperation::Burn { + token: token.clone(), + amount: amount.into(), + post_balance, + target_account: UserAccount::Internal(target.clone()), + }, + }); + Ok(()) + } +} diff --git a/crates/tx_prelude/src/ibc.rs b/crates/tx_prelude/src/ibc.rs index 6915c2f0b2..d82cedc461 100644 --- a/crates/tx_prelude/src/ibc.rs +++ b/crates/tx_prelude/src/ibc.rs @@ -25,13 +25,14 @@ use crate::{Ctx, Error}; /// execution. pub fn ibc_actions( ctx: &mut Ctx, -) -> IbcActions<'_, Ctx, crate::parameters::Store> { +) -> IbcActions<'_, Ctx, crate::parameters::Store, crate::token::Store> +{ let ctx = Rc::new(RefCell::new(ctx.clone())); let verifiers = Rc::new(RefCell::new(BTreeSet::
::new())); let mut actions = IbcActions::new(ctx.clone(), verifiers.clone()); let module = TransferModule::new(ctx.clone(), verifiers); actions.add_transfer_module(module); - let module = NftTransferModule::new(ctx); + let module = NftTransferModule::>::new(ctx); actions.add_transfer_module(module); actions } @@ -74,7 +75,7 @@ impl IbcStorageContext for Ctx { token: &Address, amount: Amount, ) -> Result<(), Error> { - mint_tokens(self, target, token, amount) + mint_tokens::<_, crate::token::Store<_>>(self, target, token, amount) } fn burn_token( @@ -83,7 +84,7 @@ impl IbcStorageContext for Ctx { token: &Address, amount: Amount, ) -> Result<(), Error> { - burn_tokens(self, target, token, amount) + burn_tokens::<_, crate::token::Store<_>>(self, target, token, amount) } fn insert_verifier(&mut self, addr: &Address) -> Result<(), Error> { diff --git a/wasm/Cargo.lock b/wasm/Cargo.lock index 7204e17aad..75caeddb4c 100644 --- a/wasm/Cargo.lock +++ b/wasm/Cargo.lock @@ -3838,7 +3838,6 @@ dependencies = [ "namada_state", "namada_storage", "namada_systems", - "namada_token", "namada_tx", "namada_vp", "primitive-types", diff --git a/wasm/tx_ibc/src/lib.rs b/wasm/tx_ibc/src/lib.rs index 78963875f4..4f992ee798 100644 --- a/wasm/tx_ibc/src/lib.rs +++ b/wasm/tx_ibc/src/lib.rs @@ -11,8 +11,9 @@ use namada_tx_prelude::*; #[transaction] fn apply_tx(ctx: &mut Ctx, tx_data: BatchedTx) -> TxResult { let data = ctx.get_tx_data(&tx_data)?; - let (transfer, masp_tx) = - ibc::ibc_actions(ctx).execute(&data).into_storage_result()?; + let (transfer, masp_tx) = ibc::ibc_actions(ctx) + .execute::(&data) + .into_storage_result()?; let masp_section_ref = if let Some(transfers) = transfer { // Prepare the sources of the multi-transfer diff --git a/wasm_for_tests/Cargo.lock b/wasm_for_tests/Cargo.lock index 7b85b1e508..e675829d5e 100644 --- a/wasm_for_tests/Cargo.lock +++ b/wasm_for_tests/Cargo.lock @@ -3908,7 +3908,6 @@ dependencies = [ "namada_state", "namada_storage", "namada_systems", - "namada_token", "namada_tx", "namada_vp", "primitive-types",