Skip to content

Commit

Permalink
test callback
Browse files Browse the repository at this point in the history
  • Loading branch information
taitruong committed Jun 7, 2024
1 parent a2608dc commit 05c3687
Show file tree
Hide file tree
Showing 3 changed files with 111 additions and 36 deletions.
10 changes: 2 additions & 8 deletions packages/ics721/src/ibc_packet_receive.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ use crate::{
load_nft_contract_for_class_id, query_get_instantiate2_nft_contract,
query_nft_contract_for_class_id,
},
state::{CW721_CODE_ID, OUTGOING_CLASS_TOKEN_TO_CHANNEL, PO},
state::{OUTGOING_CLASS_TOKEN_TO_CHANNEL, PO},
token_types::{VoucherCreation, VoucherRedemption},
ContractError,
};
Expand Down Expand Up @@ -240,13 +240,7 @@ fn create_callback_msg(
Some(nft_contract) => Ok(nft_contract),
None => {
// contract not yet instantiated, so we use instantiate2 to get the contract address
let cw721_code_id = CW721_CODE_ID.load(deps.storage)?;
query_get_instantiate2_nft_contract(
deps,
env,
local_class_id.clone(),
Some(cw721_code_id),
)
query_get_instantiate2_nft_contract(deps, env, local_class_id.clone(), None)
}
}
}?;
Expand Down
2 changes: 2 additions & 0 deletions packages/ics721/src/query.rs
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,8 @@ pub fn query_nft_contract_for_class_id(
.map(|e| e.map(|(_, v)| v.address))
}

/// Returns the address of the instantiated NFT contract for the given class_id.
/// If cw721_code_id is None, it will use the default CW721_CODE_ID.
pub fn query_get_instantiate2_nft_contract(
deps: Deps,
env: &Env,
Expand Down
135 changes: 107 additions & 28 deletions packages/ics721/src/testing/ibc_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@ use crate::{
};
use ics721_types::{
ibc_types::NonFungibleTokenPacketData,
token_types::{ClassId, TokenId},
types::{Ics721Callbacks, ReceiverExecuteMsg},
token_types::{Class, ClassId, TokenId},
types::{Ics721Callbacks, Ics721Memo, ReceiverExecuteMsg},
};

const CONTRACT_PORT: &str = "wasm.address1";
Expand All @@ -32,9 +32,11 @@ const CONNECTION_ID: &str = "connection-2";
const CHANNEL_ID: &str = "channel-1";
const DEFAULT_TIMEOUT: u64 = 42; // Seconds.

const ADDR1: &str = "addr1";
const ADDR_ICS721: &str = "addr_ics721";
const RELAYER_ADDR: &str = "relayer";
const CW721_CODE_ID: u64 = 0;
const ADDR_CW721: &str = "addr_cw721";
const ADDR_NFT_RECEIVER: &str = "nft_receiver";

#[derive(Default)]
pub struct Ics721Contract {}
Expand All @@ -48,6 +50,13 @@ impl Ics721Execute<Empty> for Ics721Contract {
impl Ics721Ibc<Empty> for Ics721Contract {}
impl Ics721Query for Ics721Contract {}

#[cw_serde]
pub struct CallbackData {
pub token_id: String,
/// NFT owner on source chain, on ack this sender also receives a POAP
pub sender: String,
}

fn mock_channel(channel_id: &str) -> IbcChannel {
IbcChannel::new(
IbcEndpoint {
Expand Down Expand Up @@ -80,6 +89,24 @@ fn mock_packet(data: Binary) -> IbcPacket {
)
}

fn create_memo(
sender: String,
token_id: String,
ack_callback_addr: Option<String>,
receive_callback_addr: Option<String>,
) -> Ics721Memo {
let callback_data = Some(to_json_binary(&CallbackData { sender, token_id }).unwrap());
let callbacks = Ics721Callbacks {
ack_callback_data: callback_data.clone(),
ack_callback_addr,
receive_callback_data: callback_data,
receive_callback_addr,
};
Ics721Memo {
callbacks: Some(callbacks),
}
}

fn add_channel(mut deps: DepsMut, env: Env, channel_id: &str) {
let channel = mock_channel(channel_id);
let open_msg = IbcChannelOpenMsg::new_init(channel.clone());
Expand Down Expand Up @@ -231,7 +258,7 @@ fn test_ibc_channel_open() {
let env = mock_env();

// Instantiate the contract
do_instantiate(deps.as_mut(), env.clone(), ADDR1).unwrap();
do_instantiate(deps.as_mut(), env.clone(), ADDR_ICS721).unwrap();

// Add channel calls open and connect valid
add_channel(deps.as_mut(), env, "channel-1");
Expand All @@ -244,7 +271,7 @@ fn test_ibc_channel_open_ordered_channel() {
let env = mock_env();

// Instantiate the contract
do_instantiate(deps.as_mut(), env.clone(), ADDR1).unwrap();
do_instantiate(deps.as_mut(), env.clone(), ADDR_ICS721).unwrap();

let channel_id = "channel-1";
let channel = IbcChannel::new(
Expand Down Expand Up @@ -274,7 +301,7 @@ fn test_ibc_channel_open_invalid_version() {
let env = mock_env();

// Instantiate the contract
do_instantiate(deps.as_mut(), env.clone(), ADDR1).unwrap();
do_instantiate(deps.as_mut(), env.clone(), ADDR_ICS721).unwrap();

let channel_id = "channel-1";
let channel = IbcChannel::new(
Expand Down Expand Up @@ -304,7 +331,7 @@ fn test_ibc_channel_open_invalid_version_counterparty() {
let env = mock_env();

// Instantiate the contract
do_instantiate(deps.as_mut(), env.clone(), ADDR1).unwrap();
do_instantiate(deps.as_mut(), env.clone(), ADDR_ICS721).unwrap();

let channel_id = "channel-1";
let channel = IbcChannel::new(
Expand Down Expand Up @@ -336,7 +363,7 @@ fn test_ibc_channel_connect() {
let env = mock_env();

// Instantiate the contract
do_instantiate(deps.as_mut(), env.clone(), ADDR1).unwrap();
do_instantiate(deps.as_mut(), env.clone(), ADDR_ICS721).unwrap();

// Add channel calls open and connect valid
add_channel(deps.as_mut(), env, "channel-1");
Expand All @@ -349,7 +376,7 @@ fn test_ibc_channel_connect_ordered_channel() {
let env = mock_env();

// Instantiate the contract
do_instantiate(deps.as_mut(), env.clone(), ADDR1).unwrap();
do_instantiate(deps.as_mut(), env.clone(), ADDR_ICS721).unwrap();

let channel_id = "channel-1";
let channel = IbcChannel::new(
Expand Down Expand Up @@ -379,7 +406,7 @@ fn test_ibc_channel_connect_invalid_version() {
let env = mock_env();

// Instantiate the contract
do_instantiate(deps.as_mut(), env.clone(), ADDR1).unwrap();
do_instantiate(deps.as_mut(), env.clone(), ADDR_ICS721).unwrap();

let channel_id = "channel-1";
let channel = IbcChannel::new(
Expand Down Expand Up @@ -409,7 +436,7 @@ fn test_ibc_channel_connect_invalid_version_counterparty() {
let env = mock_env();

// Instantiate the contract
do_instantiate(deps.as_mut(), env.clone(), ADDR1).unwrap();
do_instantiate(deps.as_mut(), env.clone(), ADDR_ICS721).unwrap();

let channel_id = "channel-1";
let channel = IbcChannel::new(
Expand Down Expand Up @@ -437,22 +464,51 @@ fn test_ibc_channel_connect_invalid_version_counterparty() {

#[test]
fn test_ibc_packet_receive() {
let data = to_json_binary(&NonFungibleTokenPacketData {
class_id: ClassId::new("id"),
let mut deps = mock_dependencies();
let env = mock_env();
crate::state::CW721_CODE_ID
.save(deps.as_mut().storage, &0)
.unwrap();
let class_id = ClassId::new(ADDR_CW721);
let class = Class {
id: class_id.clone(),
// There is no collection-level uri nor data in the
// cw721 specification so we set those values to
// `None` for local, cw721 NFTs.
uri: None,
data: None,
};
let sender = "violet";
let token_id = "1";
let memo = create_memo(sender.to_string(), token_id.to_string(), None, None);
let memo_string = Some(Binary::to_base64(&to_json_binary(&memo).unwrap()));
let nft_packet = NonFungibleTokenPacketData {
class_id,
class_uri: None,
class_data: None,
token_ids: vec![TokenId::new("1")],
token_ids: vec![TokenId::new(token_id.to_string())],
token_uris: None,
token_data: None,
sender: "violet".to_string(),
receiver: "blue".to_string(),
memo: None,
})
.unwrap();
sender: sender.to_string(),
receiver: ADDR_NFT_RECEIVER.to_string(),
memo: memo_string,
};
let data = to_json_binary(&nft_packet).unwrap();
let ibc_packet = mock_packet(data);
let class_id_info = ClassIdInfo {
class_id: ClassId::new(format!(
"{}/{}/{}",
ibc_packet.dest.port_id,
ibc_packet.dest.channel_id,
class.id.clone()
)),
address: Addr::unchecked(ADDR_CW721),
};
CLASS_ID_AND_NFT_CONTRACT_INFO
.save(deps.as_mut().storage, &class.id, &class_id_info)
.unwrap();

let packet = IbcPacketReceiveMsg::new(ibc_packet.clone(), Addr::unchecked(RELAYER_ADDR));
let mut deps = mock_dependencies();
let env = mock_env();
PO.set_pauser(&mut deps.storage, &deps.api, None).unwrap();
let response = Ics721Contract::default()
.ibc_packet_receive(deps.as_mut(), env, packet)
Expand All @@ -475,9 +531,9 @@ fn test_ibc_packet_receive() {
assert!(conjunction_msg.is_some());

let operands = conjunction_msg.unwrap();
assert_eq!(operands.len(), 2);
assert_eq!(operands.len(), 3);

let add_incoming_msg = operands[1].clone();
let add_incoming_msg = operands[2].clone();
match add_incoming_msg {
WasmMsg::Execute { msg, .. } => {
match from_json::<ExecuteMsg>(msg).ok() {
Expand All @@ -493,7 +549,7 @@ fn test_ibc_packet_receive() {
// assert there is only one class token to channel entry
let class_id = format!(
"{}/{}/{}",
ibc_packet.dest.port_id, ibc_packet.dest.channel_id, "id"
ibc_packet.dest.port_id, ibc_packet.dest.channel_id, ADDR_CW721
);
assert_eq!(
class_token_to_channel_list,
Expand All @@ -504,7 +560,30 @@ fn test_ibc_packet_receive() {
},
_ => panic!("unexpected execute msg"),
},
_ => panic!("no callback msg"),
_ => panic!("not a callback msg"),
}
}
_ => panic!("unexpected wasm msg"),
}

let receive_callback_msg = operands[1].clone();
match receive_callback_msg {
WasmMsg::Execute {
contract_addr,
msg,
funds: _,
} => {
assert_eq!(contract_addr, ADDR_NFT_RECEIVER);
match from_json::<ReceiverExecuteMsg>(msg).ok() {
Some(ReceiverExecuteMsg::Ics721ReceiveCallback(msg)) => {
assert_eq!(msg.nft_contract, ADDR_CW721);
assert_eq!(msg.original_packet, nft_packet);
assert_eq!(
msg.msg,
memo.callbacks.unwrap().receive_callback_data.unwrap()
);
}
_ => panic!("unexpected execute msg"),
}
}
_ => panic!("unexpected wasm msg"),
Expand Down Expand Up @@ -547,7 +626,7 @@ fn test_ibc_packet_receive_emits_memo() {
token_uris: None,
token_data: None,
sender: "violet".to_string(),
receiver: "blue".to_string(),
receiver: ADDR_NFT_RECEIVER.to_string(),
memo: Some("memo".to_string()),
})
.unwrap();
Expand Down Expand Up @@ -715,7 +794,7 @@ fn test_different_memo_ignored() {
token_uris: None,
token_data: None,
sender: "violet".to_string(),
receiver: "blue".to_string(),
receiver: ADDR_NFT_RECEIVER.to_string(),
memo: Some(
to_json_binary(&DifferentMemo {
different: Some(Ics721Callbacks {
Expand Down Expand Up @@ -768,7 +847,7 @@ fn test_ibc_packet_not_json_memo() {
token_uris: None,
token_data: None,
sender: "violet".to_string(),
receiver: "blue".to_string(),
receiver: ADDR_NFT_RECEIVER.to_string(),
memo: None,
};

Expand Down

0 comments on commit 05c3687

Please sign in to comment.