Skip to content

Commit

Permalink
fix amount
Browse files Browse the repository at this point in the history
  • Loading branch information
yito88 committed Jun 20, 2024
1 parent 5c523bd commit 8af4dcb
Show file tree
Hide file tree
Showing 2 changed files with 83 additions and 79 deletions.
48 changes: 38 additions & 10 deletions crates/ibc/src/context/token_transfer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,15 @@ use ibc::apps::transfer::context::{
};
use ibc::apps::transfer::types::error::TokenTransferError;
use ibc::apps::transfer::types::{Memo, PrefixedCoin, PrefixedDenom};
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_token::Amount;
use namada_core::uint::Uint;
use namada_token::{read_denom, Amount, Denomination};

use super::common::IbcCommonContext;
use crate::{get_token_amount, storage, IBC_ESCROW_ADDRESS};
use crate::{storage, IBC_ESCROW_ADDRESS};

/// Token transfer context to handle tokens
#[derive(Debug)]
Expand Down Expand Up @@ -44,6 +46,36 @@ where
self.verifiers.borrow_mut().insert(addr.clone());
}

/// Get the token address and the amount from PrefixedCoin. If the base
/// denom is not an address, it returns `IbcToken`
fn get_token_amount(
&self,
coin: &PrefixedCoin,
) -> Result<(Address, Amount), TokenTransferError> {
let token = match Address::decode(coin.denom.base_denom.as_str()) {
Ok(token_addr) if coin.denom.trace_path.is_empty() => token_addr,
_ => storage::ibc_token(coin.denom.to_string()),
};

// Convert IBC amount to Namada amount for the token
let denom = read_denom(&*self.inner.borrow(), &token)
.map_err(ContextError::from)?
.unwrap_or(Denomination(0));
let uint_amount = Uint(primitive_types::U256::from(coin.amount).0);
let amount = Amount::from_uint(uint_amount, denom).map_err(|e| {
TokenTransferError::ContextError(
ChannelError::Other {
description: format!(
"The IBC amount is invalid: Coin {coin}, Error {e}",
),
}
.into(),
)
})?;

Ok((token, amount))
}

/// Update the mint amount of the token
fn update_mint_amount(
&self,
Expand Down Expand Up @@ -211,8 +243,7 @@ where
coin: &PrefixedCoin,
_memo: &Memo,
) -> Result<(), TokenTransferError> {
let (ibc_token, amount) =
get_token_amount(&*self.inner.borrow(), coin)?;
let (ibc_token, amount) = self.get_token_amount(coin)?;

self.add_withdraw(&ibc_token, amount)?;

Expand Down Expand Up @@ -241,8 +272,7 @@ where
_channel_id: &ChannelId,
coin: &PrefixedCoin,
) -> Result<(), TokenTransferError> {
let (ibc_token, amount) =
get_token_amount(&*self.inner.borrow(), coin)?;
let (ibc_token, amount) = self.get_token_amount(coin)?;

self.add_deposit(&ibc_token, amount)?;

Expand All @@ -258,8 +288,7 @@ where
coin: &PrefixedCoin,
) -> Result<(), TokenTransferError> {
// The trace path of the denom is already updated if receiving the token
let (ibc_token, amount) =
get_token_amount(&*self.inner.borrow(), coin)?;
let (ibc_token, amount) = self.get_token_amount(coin)?;

self.update_mint_amount(&ibc_token, amount, true)?;
self.add_deposit(&ibc_token, amount)?;
Expand Down Expand Up @@ -287,8 +316,7 @@ where
coin: &PrefixedCoin,
_memo: &Memo,
) -> Result<(), TokenTransferError> {
let (ibc_token, amount) =
get_token_amount(&*self.inner.borrow(), coin)?;
let (ibc_token, amount) = self.get_token_amount(coin)?;

self.update_mint_amount(&ibc_token, amount, false)?;
self.add_withdraw(&ibc_token, amount)?;
Expand Down
114 changes: 45 additions & 69 deletions crates/ibc/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,8 +58,7 @@ use ibc::apps::transfer::handler::{
use ibc::apps::transfer::types::error::TokenTransferError;
use ibc::apps::transfer::types::packet::PacketData;
use ibc::apps::transfer::types::{
is_receiver_chain_source, PrefixedCoin, PrefixedDenom, TracePath,
TracePrefix,
is_receiver_chain_source, PrefixedDenom, TracePath, TracePrefix,
};
use ibc::core::channel::types::acknowledgement::{
Acknowledgement, AcknowledgementStatus,
Expand All @@ -81,8 +80,7 @@ pub use ibc::*;
pub use msg::*;
use namada_core::address::{self, Address};
use namada_core::uint::Uint;
use namada_storage::StorageRead;
use namada_token::{read_denom, Amount, Denomination, ShieldingTransfer};
use namada_token::{Amount, ShieldingTransfer};
pub use nft::*;
use prost::Message;
use thiserror::Error;
Expand Down Expand Up @@ -361,55 +359,60 @@ where
} else {
&packet.port_id_on_b
};
let (ibc_trace, amount) =
if *my_port_id == PortId::transfer() {
let packet_data =
serde_json::from_slice::<PacketData>(&packet.data)
.map_err(|e| {
Error::TokenTransfer(TokenTransferError::Other(
format!("Decoding the packet data failed: {e}"),
))
})?;
let ibc_denom = packet_data.token.denom.to_string();
let (_, amount) = get_token_amount::<C>(
&*self.ctx.inner.borrow(),
&packet_data.token,
)
.map_err(Error::TokenTransfer)?;
(ibc_denom, amount)
} else {
let packet_data =
serde_json::from_slice::<NftPacketData>(&packet.data)
.map_err(|e| {
Error::TokenTransfer(TokenTransferError::Other(
format!("Decoding the packet data failed: {e}"),
))
})?;
let ibc_trace = format!(
"{}/{}",
&packet_data.class_id,
packet_data
.token_ids
.0
.first()
.expect("TokenID should exist"),
);
(ibc_trace, Amount::from_u64(1))
};
let (ibc_trace, amount) = if *my_port_id == PortId::transfer() {
let packet_data = serde_json::from_slice::<PacketData>(
&packet.data,
)
.map_err(|e| {
Error::TokenTransfer(TokenTransferError::Other(format!(
"Decoding the packet data failed: {e}"
)))
})?;
let ibc_denom = packet_data.token.denom.to_string();
let uint_amount =
Uint(primitive_types::U256::from(packet_data.token.amount).0);
// amount should be canonical
let amount = Amount::from_uint(uint_amount, 0).map_err(|e| {
Error::TokenTransfer(TokenTransferError::Other(format!(
"Invalid amount: {}, error {e}",
packet_data.token.amount
)))
})?;
(ibc_denom, amount)
} else {
let packet_data = serde_json::from_slice::<NftPacketData>(
&packet.data,
)
.map_err(|e| {
Error::TokenTransfer(TokenTransferError::Other(format!(
"Decoding the packet data failed: {e}"
)))
})?;
let ibc_trace = format!(
"{}/{}",
&packet_data.class_id,
packet_data
.token_ids
.0
.first()
.expect("TokenID should exist"),
);
(ibc_trace, Amount::from_u64(1))
};

let ibc_token = if is_sender {
if ibc_trace.contains('/') {
ibc_token(ibc_trace)
ibc_token(&ibc_trace)
} else {
Address::decode(ibc_trace).map_err(|e| {
Address::decode(&ibc_trace).map_err(|e| {
Error::TokenTransfer(TokenTransferError::Other(format!(
"Invalid IBC trace: {e}"
)))
})?
}
} else {
received_ibc_token(
ibc_trace,
&ibc_trace,
&packet.port_id_on_a,
&packet.chan_id_on_a,
&packet.port_id_on_b,
Expand Down Expand Up @@ -475,33 +478,6 @@ pub fn decode_message(tx_data: &[u8]) -> Result<IbcMessage, Error> {
Err(Error::DecodingData)
}

/// Get the token address and the amount from `PrefixedCoin`
pub fn get_token_amount<S>(
state: &S,
coin: &PrefixedCoin,
) -> Result<(Address, Amount), TokenTransferError>
where
S: StorageRead,
{
let token = match Address::decode(coin.denom.base_denom.as_str()) {
Ok(token_addr) if coin.denom.trace_path.is_empty() => token_addr,
_ => storage::ibc_token(coin.denom.to_string()),
};

// Convert IBC amount to Namada amount for the token
let denom = read_denom(state, &token)
.map_err(ContextError::from)?
.unwrap_or(Denomination(0));
let uint_amount = Uint(primitive_types::U256::from(coin.amount).0);
let amount = Amount::from_uint(uint_amount, denom).map_err(|e| {
TokenTransferError::Other(format!(
"The IBC amount is invalid: Coin {coin}, Error {e}",
))
})?;

Ok((token, amount))
}

fn received_ibc_trace(
base_trace: impl AsRef<str>,
src_port_id: &PortId,
Expand Down

0 comments on commit 8af4dcb

Please sign in to comment.