Skip to content

Commit

Permalink
fix messages and serde
Browse files Browse the repository at this point in the history
  • Loading branch information
yito88 committed Jan 3, 2024
1 parent 27ee86a commit 8dfda81
Show file tree
Hide file tree
Showing 14 changed files with 358 additions and 126 deletions.
4 changes: 2 additions & 2 deletions ibc-apps/ics20-transfer/types/src/msgs/transfer.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
//! Defines the token transfer message type
//! Defines the Non-Fungible Token Transfer message type
use ibc_core::channel::types::error::PacketError;
use ibc_core::channel::types::timeout::TimeoutHeight;
Expand All @@ -15,7 +15,7 @@ use crate::packet::PacketData;

pub(crate) const TYPE_URL: &str = "/ibc.applications.transfer.v1.MsgTransfer";

/// Message used to build an ICS20 token transfer packet.
/// Message used to build an ICS-721 Non-Fungible Token Transfer packet.
///
/// Note that this message is not a packet yet, as it lacks the proper sequence
/// number, and destination port/channel. This is by design. The sender of the
Expand Down
23 changes: 9 additions & 14 deletions ibc-apps/ics721-nft-transfer/src/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,27 +11,27 @@ use crate::types::{

pub trait NftContext {
/// Get the class ID of the token
fn get_class_id(&self) -> ClassId;
fn get_class_id(&self) -> &ClassId;

/// Get the token ID
fn get_id(&self) -> TokenId;
fn get_id(&self) -> &TokenId;

/// Get the token URI
fn get_uri(&self) -> TokenUri;
fn get_uri(&self) -> &TokenUri;

/// Get the token Data
fn get_data(&self) -> TokenData;
fn get_data(&self) -> &TokenData;
}

pub trait NftClassContext {
/// Get the class ID
fn get_id(&self) -> ClassId;
fn get_id(&self) -> &ClassId;

/// Get the class URI
fn get_uri(&self) -> ClassUri;
fn get_uri(&self) -> &ClassUri;

/// Get the class Data
fn get_data(&self) -> ClassData;
fn get_data(&self) -> &ClassData;
}

/// Read-only methods required in NFT transfer validation context.
Expand Down Expand Up @@ -59,6 +59,7 @@ pub trait NftTransferValidationContext {

/// Validates that the tokens can be escrowed successfully.
///
/// The owner of the NFT should be checked in this validation.
/// `memo` field allows to incorporate additional contextual details in the
/// escrow validation.
fn escrow_nft_validate(
Expand Down Expand Up @@ -93,6 +94,7 @@ pub trait NftTransferValidationContext {

/// Validates the sender account and the coin input before burning.
///
/// The owner of the NFT should be checked in this validation.
/// `memo` field allows to incorporate additional contextual details in the
/// burn validation.
fn burn_nft_validate(
Expand All @@ -109,13 +111,6 @@ pub trait NftTransferValidationContext {
None
}

/// Returns the current owner of the NFT
fn get_owner(
&self,
class_id: &PrefixedClassId,
token_id: &TokenId,
) -> Result<Self::AccountId, NftTransferError>;

/// Returns the NFT
fn get_nft(
&self,
Expand Down
24 changes: 8 additions & 16 deletions ibc-apps/ics721-nft-transfer/src/handler/send_transfer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,14 +70,6 @@ where
packet_data.token_uris.clear();
packet_data.token_data.clear();
for token_id in token_ids.as_ref() {
// Check the sender
let owner = transfer_ctx.get_owner(class_id, token_id)?;
if owner != sender {
return Err(NftTransferError::InvalidOwner {
sender: packet_data.sender.to_string(),
});
}

if is_sender_chain_source(msg.port_id_on_a.clone(), msg.chan_id_on_a.clone(), class_id) {
transfer_ctx.escrow_nft_validate(
&sender,
Expand All @@ -91,13 +83,13 @@ where
transfer_ctx.burn_nft_validate(&sender, class_id, token_id, &packet_data.memo)?;
}
let nft = transfer_ctx.get_nft(class_id, token_id)?;
packet_data.token_uris.push(nft.get_uri());
packet_data.token_data.push(nft.get_data());
packet_data.token_uris.push(nft.get_uri().clone());
packet_data.token_data.push(nft.get_data().clone());
}

let nft_class = transfer_ctx.get_nft_class(class_id)?;
packet_data.class_uri = Some(nft_class.get_uri());
packet_data.class_data = Some(nft_class.get_data());
packet_data.class_uri = Some(nft_class.get_uri().clone());
packet_data.class_data = Some(nft_class.get_data().clone());

let packet = {
let data = serde_json::to_vec(&packet_data)
Expand Down Expand Up @@ -174,13 +166,13 @@ where
transfer_ctx.burn_nft_execute(&sender, class_id, token_id, &packet_data.memo)?;
}
let nft = transfer_ctx.get_nft(class_id, token_id)?;
packet_data.token_uris.push(nft.get_uri());
packet_data.token_data.push(nft.get_data());
packet_data.token_uris.push(nft.get_uri().clone());
packet_data.token_data.push(nft.get_data().clone());
}

let nft_class = transfer_ctx.get_nft_class(class_id)?;
packet_data.class_uri = Some(nft_class.get_uri());
packet_data.class_data = Some(nft_class.get_data());
packet_data.class_uri = Some(nft_class.get_uri().clone());
packet_data.class_data = Some(nft_class.get_data().clone());

let packet = {
let data = {
Expand Down
2 changes: 1 addition & 1 deletion ibc-apps/ics721-nft-transfer/src/module.rs
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,7 @@ pub fn on_chan_close_init_execute(
_port_id: &PortId,
_channel_id: &ChannelId,
) -> Result<ModuleExtras, NftTransferError> {
unimplemented!()
Err(NftTransferError::CantCloseChannel)
}

pub fn on_chan_close_confirm_validate(
Expand Down
3 changes: 2 additions & 1 deletion ibc-apps/ics721-nft-transfer/types/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,11 @@ all-features = true
borsh = { workspace = true, optional = true }
derive_more = { workspace = true }
displaydoc = { workspace = true }
http = "1.0.0"
mime = "0.3.17"
schemars = { workspace = true, optional = true }
serde = { workspace = true, optional = true }
serde_json = { workspace = true }
http = { version = "0.2.9", default-features = false }

# ibc dependencies
ibc-core = { workspace = true }
Expand Down
87 changes: 65 additions & 22 deletions ibc-apps/ics721-nft-transfer/types/src/class.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
use core::fmt::{self, Display, Error as FmtError, Formatter};
use core::str::FromStr;

use derive_more::{Display, From};
use derive_more::From;
use http::Uri;
use ibc_core::host::types::identifiers::{ChannelId, PortId};
use ibc_core::primitives::prelude::*;
Expand Down Expand Up @@ -324,26 +324,69 @@ impl Display for PrefixedClassId {
}

/// Class URI for an NFT
#[cfg_attr(
feature = "parity-scale-codec",
derive(
parity_scale_codec::Encode,
parity_scale_codec::Decode,
scale_info::TypeInfo
)
)]
#[cfg_attr(
feature = "borsh",
derive(borsh::BorshSerialize, borsh::BorshDeserialize)
)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
#[derive(Clone, Debug, PartialEq, Eq, Display)]
pub struct ClassUri(String);
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct ClassUri(
#[cfg_attr(feature = "serde", serde(with = "serializers"))]
#[cfg_attr(feature = "schema", schemars(with = "String"))]
Uri,
);

#[cfg(feature = "borsh")]
impl borsh::BorshSerialize for ClassUri {
fn serialize<W: borsh::maybestd::io::Write>(
&self,
writer: &mut W,
) -> borsh::maybestd::io::Result<()> {
borsh::BorshSerialize::serialize(&self.to_string(), writer)
}
}

impl AsRef<str> for ClassUri {
fn as_ref(&self) -> &str {
&self.0
#[cfg(feature = "borsh")]
impl borsh::BorshDeserialize for ClassUri {
fn deserialize_reader<R: borsh::maybestd::io::Read>(
reader: &mut R,
) -> borsh::maybestd::io::Result<Self> {
let uri = String::deserialize_reader(reader)?;
Ok(ClassUri::from_str(&uri).map_err(|_| borsh::maybestd::io::ErrorKind::Other)?)
}
}

#[cfg(feature = "parity-scale-codec")]
impl parity_scale_codec::Encode for ClassUri {
fn encode_to<T: parity_scale_codec::Output + ?Sized>(&self, writer: &mut T) {
self.to_string().encode_to(writer);
}
}

#[cfg(feature = "parity-scale-codec")]
impl parity_scale_codec::Decode for ClassUri {
fn decode<I: parity_scale_codec::Input>(
input: &mut I,
) -> Result<Self, parity_scale_codec::Error> {
let uri = String::decode(input)?;
ClassUri::from_str(&uri).map_err(|_| parity_scale_codec::Error::from("from str error"))
}
}

#[cfg(feature = "parity-scale-codec")]
impl scale_info::TypeInfo for ClassUri {
type Identity = Self;

fn type_info() -> scale_info::Type {
scale_info::Type::builder()
.path(scale_info::Path::new("ClassUri", module_path!()))
.composite(
scale_info::build::Fields::unnamed()
.field(|f| f.ty::<String>().type_name("String")),
)
}
}

impl Display for ClassUri {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.0)
}
}

Expand All @@ -352,7 +395,7 @@ impl FromStr for ClassUri {

fn from_str(class_uri: &str) -> Result<Self, Self::Err> {
match Uri::from_str(class_uri) {
Ok(_) => Ok(Self(class_uri.to_string())),
Ok(uri) => Ok(Self(uri)),
Err(err) => Err(NftTransferError::InvalidUri {
uri: class_uri.to_string(),
validation_error: err,
Expand Down Expand Up @@ -400,7 +443,7 @@ mod tests {
use super::*;

#[test]
fn test_denom_validation() -> Result<(), NftTransferError> {
fn test_class_id_validation() -> Result<(), NftTransferError> {
assert!(ClassId::from_str("").is_err(), "empty base class ID");
assert!(ClassId::from_str("myclass").is_ok(), "valid base class ID");
assert!(PrefixedClassId::from_str("").is_err(), "empty class trace");
Expand Down Expand Up @@ -442,7 +485,7 @@ mod tests {
}

#[test]
fn test_denom_trace() -> Result<(), NftTransferError> {
fn test_class_id_trace() -> Result<(), NftTransferError> {
assert_eq!(
PrefixedClassId::from_str("transfer/channel-0/myclass")?,
PrefixedClassId {
Expand All @@ -464,7 +507,7 @@ mod tests {
}

#[test]
fn test_denom_serde() -> Result<(), NftTransferError> {
fn test_class_id_serde() -> Result<(), NftTransferError> {
let dt_str = "transfer/channel-0/myclass";
let dt = PrefixedClassId::from_str(dt_str)?;
assert_eq!(dt.to_string(), dt_str, "valid single trace info");
Expand Down
Loading

0 comments on commit 8dfda81

Please sign in to comment.