diff --git a/cairo-contracts/packages/apps/src/tests/transfer.cairo b/cairo-contracts/packages/apps/src/tests/transfer.cairo index 6db03fc7..26cf0b9f 100644 --- a/cairo-contracts/packages/apps/src/tests/transfer.cairo +++ b/cairo-contracts/packages/apps/src/tests/transfer.cairo @@ -1,7 +1,7 @@ use TokenTransferComponent::TransferValidationTrait; use openzeppelin_testing::events::EventSpyExt; use snforge_std::cheatcodes::events::EventSpy; -use snforge_std::spy_events; +use snforge_std::{spy_events, start_cheat_caller_address}; use starknet::class_hash::class_hash_const; use starknet_ibc_apps::transfer::ERC20Contract; use starknet_ibc_apps::transfer::TokenTransferComponent::{ @@ -12,7 +12,8 @@ use starknet_ibc_core::router::{AppContract, AppContractTrait}; use starknet_ibc_testkit::configs::{TransferAppConfigTrait, TransferAppConfig}; use starknet_ibc_testkit::dummies::CLASS_HASH; use starknet_ibc_testkit::dummies::{ - AMOUNT, SUPPLY, OWNER, NAME, SYMBOL, COSMOS, STARKNET, HOSTED_DENOM, EMPTY_MEMO + AMOUNT, SUPPLY, OWNER, SN_USER, CS_USER, NAME, SYMBOL, COSMOS, STARKNET, HOSTED_DENOM, + EMPTY_MEMO }; use starknet_ibc_testkit::event_spy::TransferEventSpyExt; use starknet_ibc_testkit::handles::{ERC20Handle, AppHandle}; @@ -79,21 +80,23 @@ fn test_missing_ibc_token_address() { fn test_escrow_ok() { let (ics20, mut erc20, cfg, mut spy) = setup(); - // Owner approves the amount of allowance for the `TransferApp` contract. - erc20.approve(OWNER(), ics20.address, cfg.amount); + start_cheat_caller_address(ics20.address, SN_USER()); - let msg_transfer = cfg.dummy_msg_transfer(cfg.native_denom.clone(), STARKNET(), COSMOS()); + // User approves the amount of allowance for the `TransferApp` contract. + erc20.approve(SN_USER(), ics20.address, cfg.amount); + + let msg_transfer = cfg.dummy_msg_transfer(cfg.native_denom.clone(), CS_USER()); call_contract(ics20.address, selector!("send_transfer_internal"), @msg_transfer); // Assert the `SendEvent` emitted. spy .assert_send_event( - ics20.address, STARKNET(), COSMOS(), cfg.native_denom.clone(), cfg.amount + ics20.address, SN_USER(), CS_USER(), cfg.native_denom.clone(), cfg.amount ); // Check the balance of the sender. - erc20.assert_balance(OWNER(), SUPPLY - cfg.amount); + erc20.assert_balance(SN_USER(), SUPPLY - cfg.amount); // Check the balance of the transfer contract. erc20.assert_balance(ics20.address, cfg.amount); @@ -103,15 +106,19 @@ fn test_escrow_ok() { fn test_unescrow_ok() { let (ics20, mut erc20, cfg, mut spy) = setup(); - // Owner approves the amount of allowance for the `TransferApp` contract. - erc20.approve(OWNER(), ics20.address, cfg.amount); + start_cheat_caller_address(ics20.address, SN_USER()); + + // User approves the amount of allowance for the `TransferApp` contract. + erc20.approve(SN_USER(), ics20.address, cfg.amount); - let msg_transfer = cfg.dummy_msg_transfer(cfg.native_denom.clone(), STARKNET(), COSMOS()); + let msg_transfer = cfg.dummy_msg_transfer(cfg.native_denom.clone(), CS_USER()); call_contract(ics20.address, selector!("send_transfer_internal"), @msg_transfer); spy.drop_all_events(); + start_cheat_caller_address(ics20.address, OWNER()); + let prefixed_denom = cfg.prefix_native_denom(); let recv_packet = cfg.dummy_packet(prefixed_denom.clone(), COSMOS(), STARKNET()); @@ -120,12 +127,12 @@ fn test_unescrow_ok() { ics20.on_recv_packet(recv_packet); // Assert the `RecvEvent` emitted. - spy.assert_recv_event(ics20.address, COSMOS(), STARKNET(), prefixed_denom, cfg.amount, true); + spy.assert_recv_event(ics20.address, CS_USER(), SN_USER(), prefixed_denom, cfg.amount, true); erc20.assert_balance(ics20.address, 0); // Check the balance of the recipient. - erc20.assert_balance(OWNER(), SUPPLY); + erc20.assert_balance(SN_USER(), SUPPLY); } #[test] @@ -147,7 +154,7 @@ fn test_mint_ok() { // Assert the `RecvEvent` emitted. spy .assert_recv_event( - ics20.address, COSMOS(), STARKNET(), prefixed_denom.clone(), cfg.amount, true + ics20.address, CS_USER(), SN_USER(), prefixed_denom.clone(), cfg.amount, true ); spy.drop_all_events(); @@ -158,13 +165,13 @@ fn test_mint_ok() { // Assert the `RecvEvent` emitted. spy .assert_recv_event( - ics20.address, COSMOS(), STARKNET(), prefixed_denom.clone(), cfg.amount, true + ics20.address, CS_USER(), SN_USER(), prefixed_denom.clone(), cfg.amount, true ); let erc20: ERC20Contract = token_address.into(); // Check the balance of the receiver. - erc20.assert_balance(OWNER(), cfg.amount * 2); + erc20.assert_balance(SN_USER(), cfg.amount * 2); // Check the total supply of the ERC20 contract. erc20.assert_total_supply(cfg.amount * 2); @@ -183,24 +190,29 @@ fn test_burn_ok() { let token_address = ics20.ibc_token_address(prefixed_denom.key()); - let erc20: ERC20Contract = token_address.into(); + let mut erc20: ERC20Contract = token_address.into(); spy.drop_all_events(); - let msg_transfer = cfg.dummy_msg_transfer(prefixed_denom.clone(), STARKNET(), COSMOS()); + start_cheat_caller_address(ics20.address, SN_USER()); + + // User approves the amount of allowance for the `TransferApp` contract. + erc20.approve(SN_USER(), ics20.address, cfg.amount); + + let msg_transfer = cfg.dummy_msg_transfer(prefixed_denom.clone(), CS_USER()); call_contract(ics20.address, selector!("send_transfer_internal"), @msg_transfer); // Assert the `SendEvent` emitted. - spy.assert_send_event(ics20.address, STARKNET(), COSMOS(), prefixed_denom, cfg.amount); + spy.assert_send_event(ics20.address, SN_USER(), CS_USER(), prefixed_denom, cfg.amount); // Check the balance of the sender. - erc20.assert_balance(OWNER(), 0); + erc20.assert_balance(SN_USER(), 0); // Check the balance of the `TransferApp` contract. erc20.assert_balance(ics20.address, 0); - // Chekck the total supply of the ERC20 contract. + // Check the total supply of the ERC20 contract. erc20.assert_total_supply(0); } @@ -208,5 +220,5 @@ fn test_burn_ok() { #[should_panic(expected: 'ICS20: missing token address')] fn test_burn_non_existence_ibc_token() { let state = setup_component(); - state.burn_validate(OWNER(), HOSTED_DENOM(), AMOUNT, EMPTY_MEMO()); + state.burn_validate(SN_USER(), HOSTED_DENOM(), AMOUNT, EMPTY_MEMO()); } diff --git a/cairo-contracts/packages/apps/src/transfer/components/transfer.cairo b/cairo-contracts/packages/apps/src/transfer/components/transfer.cairo index 3ee06473..06d15d13 100644 --- a/cairo-contracts/packages/apps/src/transfer/components/transfer.cairo +++ b/cairo-contracts/packages/apps/src/transfer/components/transfer.cairo @@ -16,7 +16,7 @@ pub mod TokenTransferComponent { use starknet::{get_contract_address, get_caller_address}; use starknet_ibc_apps::transfer::types::{ MsgTransfer, PrefixedDenom, Denom, DenomTrait, PacketData, Memo, TracePrefixTrait, - PrefixedDenomTrait, Participant + PrefixedDenomTrait, Participant, ParticipantTrait, }; use starknet_ibc_apps::transfer::{ ITransferrable, ISendTransfer, ITransferQuery, ERC20Contract, ERC20ContractTrait, @@ -52,9 +52,9 @@ pub mod TokenTransferComponent { #[derive(Debug, Drop, Serde, starknet::Event)] pub struct SendEvent { #[key] - pub sender: Participant, + pub sender: ContractAddress, #[key] - pub receiver: Participant, + pub receiver: ByteArray, #[key] pub denom: PrefixedDenom, pub amount: u256, @@ -64,9 +64,9 @@ pub mod TokenTransferComponent { #[derive(Debug, Drop, Serde, starknet::Event)] pub struct RecvEvent { #[key] - pub sender: Participant, + pub sender: ByteArray, #[key] - pub receiver: Participant, + pub receiver: ContractAddress, #[key] pub denom: PrefixedDenom, pub amount: u256, @@ -77,9 +77,9 @@ pub mod TokenTransferComponent { #[derive(Debug, Drop, Serde, starknet::Event)] pub struct AckEvent { #[key] - pub sender: Participant, + pub sender: ContractAddress, #[key] - pub receiver: Participant, + pub receiver: ByteArray, #[key] pub denom: PrefixedDenom, pub amount: u256, @@ -96,7 +96,7 @@ pub mod TokenTransferComponent { #[derive(Debug, Drop, Serde, starknet::Event)] pub struct TimeoutEvent { #[key] - pub receiver: Participant, + pub receiver: ByteArray, #[key] pub denom: PrefixedDenom, pub amount: u256, @@ -149,7 +149,9 @@ pub mod TokenTransferComponent { // packet is first executed in the core contract, followed by execution // at the application level. fn send_transfer(ref self: ComponentState, msg: MsgTransfer) { - self.send_validate(msg.clone()); + let sender = get_caller_address(); + + self.send_validate(msg.clone(), sender); let channel: ChannelContract = self.owner().into(); @@ -157,7 +159,7 @@ pub mod TokenTransferComponent { channel.send_packet(packet); - self.send_execute(msg); + self.send_execute(msg, sender); } } @@ -295,64 +297,49 @@ pub mod TokenTransferComponent { +ITransferrable, +Drop > of SendTransferInternalTrait { - fn send_validate(self: @ComponentState, msg: MsgTransfer) { + fn send_validate( + self: @ComponentState, msg: MsgTransfer, sender: ContractAddress + ) { self.get_contract().can_send(); msg.validate_basic(); - let sender: Option = msg.packet_data.sender.clone().try_into(); + assert(sender.is_non_zero(), TransferErrors::ZERO_SENDER); - assert(sender.is_some(), TransferErrors::INVALID_SENDER); - - match @msg.packet_data.denom.base { + match @msg.denom.base { Denom::Native(erc20_token) => { self .escrow_validate( - sender.unwrap(), + sender, msg.port_id_on_a.clone(), msg.chan_id_on_a.clone(), erc20_token.clone(), - msg.packet_data.amount, - msg.packet_data.memo.clone(), + msg.amount, + msg.memo.clone(), ); }, Denom::Hosted(_) => { - self - .burn_validate( - sender.unwrap(), - msg.packet_data.denom.clone(), - msg.packet_data.amount, - msg.packet_data.memo.clone(), - ); + self.burn_validate(sender, msg.denom.clone(), msg.amount, msg.memo.clone(),); } } } - fn send_execute(ref self: ComponentState, msg: MsgTransfer) { - let sender: Option = msg.packet_data.sender.clone().try_into(); - - match @msg.packet_data.denom.base { + fn send_execute( + ref self: ComponentState, msg: MsgTransfer, sender: ContractAddress + ) { + match @msg.denom.base { Denom::Native(erc20_token) => { - self - .escrow_execute( - sender.unwrap(), - erc20_token.clone(), - msg.packet_data.amount, - msg.packet_data.memo.clone(), - ); + self.escrow_execute(sender, erc20_token.clone(), msg.amount, msg.memo.clone(),); }, Denom::Hosted(_) => { - self - .burn_execute( - sender.unwrap(), - msg.packet_data.denom.clone(), - msg.packet_data.amount, - msg.packet_data.memo.clone(), - ); + self.burn_execute(sender, msg.denom.clone(), msg.amount, msg.memo.clone(),); } } - self.emit_send_event(msg.packet_data); + self + .emit_send_event( + sender, msg.receiver.clone(), msg.denom.clone(), msg.amount, msg.memo.clone() + ) } fn construct_send_packet( @@ -370,7 +357,15 @@ pub mod TokenTransferComponent { let mut data: Array = ArrayTrait::new(); - msg.packet_data.serialize(ref data); + let packet_data = PacketData { + sender: Participant::Native(get_caller_address()), + receiver: Participant::External(msg.receiver.clone()), + denom: msg.denom.clone(), + amount: msg.amount, + memo: msg.memo.clone(), + }; + + packet_data.serialize(ref data); Packet { seq_on_a, @@ -415,6 +410,9 @@ pub mod TokenTransferComponent { packet_data.validate_basic(); + assert(packet_data.sender.external().is_some(), TransferErrors::INVALID_SENDER); + assert(packet_data.receiver.native().is_some(), TransferErrors::INVALID_RECEIVER); + match @packet_data.denom.base { Denom::Native(erc20_token) => { self @@ -480,6 +478,7 @@ pub mod TokenTransferComponent { (packet_data, ack_status) } + fn ack_validate( self: @ComponentState, packet: @Packet, @@ -490,6 +489,8 @@ pub mod TokenTransferComponent { packet_data.validate_basic(); + assert(packet_data.sender.native().is_some(), TransferErrors::INVALID_SENDER); + assert(packet_data.receiver.external().is_some(), TransferErrors::INVALID_RECEIVER); assert(ack_status.is_non_empty(), TransferErrors::EMPTY_ACK_STATUS); if ack_status.is_error() { @@ -527,6 +528,8 @@ pub mod TokenTransferComponent { packet_data.validate_basic(); + assert(packet_data.receiver.external().is_some(), TransferErrors::INVALID_RECEIVER); + self.refund_validate(packet.clone(), packet_data.clone()); } @@ -885,17 +888,15 @@ pub mod TokenTransferComponent { pub(crate) impl TransferEventImpl< TContractState, +HasComponent, +Drop > of TransferEventTrait { - fn emit_send_event(ref self: ComponentState, packet_data: PacketData) { - self - .emit( - SendEvent { - sender: packet_data.sender, - receiver: packet_data.receiver, - denom: packet_data.denom, - amount: packet_data.amount, - memo: packet_data.memo, - } - ); + fn emit_send_event( + ref self: ComponentState, + sender: ContractAddress, + receiver: ByteArray, + denom: PrefixedDenom, + amount: u256, + memo: Memo + ) { + self.emit(SendEvent { sender, receiver, denom, amount, memo }); } fn emit_recv_event( @@ -904,8 +905,8 @@ pub mod TokenTransferComponent { self .emit( RecvEvent { - sender: packet_data.sender, - receiver: packet_data.receiver, + sender: packet_data.sender.external().unwrap(), + receiver: packet_data.receiver.native().unwrap(), denom: packet_data.denom, amount: packet_data.amount, memo: packet_data.memo, @@ -920,8 +921,14 @@ pub mod TokenTransferComponent { self .emit( AckEvent { - sender: packet_data.sender, - receiver: packet_data.receiver, + sender: packet_data + .sender + .native() + .unwrap(), // NOTE: Safe to unwrap, since it's checked in the validation. + receiver: packet_data + .receiver + .external() + .unwrap(), // NOTE: Safe to unwrap, since it's checked in the validation. denom: packet_data.denom, amount: packet_data.amount, memo: packet_data.memo, @@ -938,7 +945,10 @@ pub mod TokenTransferComponent { self .emit( TimeoutEvent { - receiver: packet_data.receiver, + receiver: packet_data + .receiver + .external() + .unwrap(), // NOTE: Safe to unwrap, since it's checked in the validation. denom: packet_data.denom, amount: packet_data.amount, memo: packet_data.memo, diff --git a/cairo-contracts/packages/apps/src/transfer/errors.cairo b/cairo-contracts/packages/apps/src/transfer/errors.cairo index a775ba33..9818b30e 100644 --- a/cairo-contracts/packages/apps/src/transfer/errors.cairo +++ b/cairo-contracts/packages/apps/src/transfer/errors.cairo @@ -2,6 +2,7 @@ pub mod TransferErrors { pub const INVALID_SENDER: felt252 = 'ICS20: Invalid sender account'; pub const INVALID_RECEIVER: felt252 = 'ICS20: Invalid receiver account'; pub const ZERO_OWNER: felt252 = 'ICS20: owner is 0'; + pub const ZERO_SENDER: felt252 = 'ICS20: sender is 0'; pub const ZERO_ERC20_CLASS_HASH: felt252 = 'ICS20: erc20 class hash is 0'; pub const ZERO_AMOUNT: felt252 = 'ICS20: transfer amount is 0'; pub const ZERO_SALT: felt252 = 'ICS20: salt is 0'; diff --git a/cairo-contracts/packages/apps/src/transfer/types.cairo b/cairo-contracts/packages/apps/src/transfer/types.cairo index 1c0d284a..a9f57fbf 100644 --- a/cairo-contracts/packages/apps/src/transfer/types.cairo +++ b/cairo-contracts/packages/apps/src/transfer/types.cairo @@ -19,7 +19,10 @@ pub(crate) const MAXIMUM_MEMO_LENGTH: u32 = 32768; pub struct MsgTransfer { pub port_id_on_a: PortId, pub chan_id_on_a: ChannelId, - pub packet_data: PacketData, + pub denom: PrefixedDenom, + pub amount: u256, + pub receiver: ByteArray, + pub memo: Memo, pub timeout_height_on_b: Height, pub timeout_timestamp_on_b: Timestamp, } @@ -28,7 +31,9 @@ impl MsgTransferValidateBasic of ValidateBasic { fn validate_basic(self: @MsgTransfer) { self.port_id_on_a.validate(TRANSFER_PORT_ID_HASH); self.chan_id_on_a.validate(); - self.packet_data.validate_basic(); + assert(self.denom.base.is_non_zero(), TransferErrors::INVALID_DENOM); + assert(self.receiver.len() > 0, TransferErrors::INVALID_RECEIVER); + assert(self.amount.is_non_zero(), TransferErrors::ZERO_AMOUNT); } } @@ -210,6 +215,22 @@ pub enum Participant { #[generate_trait] pub impl ParticipantImpl of ParticipantTrait { + fn native(self: @Participant) -> Option { + if let Participant::Native(contract_address) = self { + Option::Some(*contract_address) + } else { + Option::None + } + } + + fn external(self: @Participant) -> Option { + if let Participant::External(byte_array) = self { + Option::Some(byte_array.clone()) + } else { + Option::None + } + } + fn is_non_zero(self: @Participant) -> bool { match self { Participant::Native(contract_address) => contract_address.is_non_zero(), @@ -283,7 +304,7 @@ pub mod tests { fn test_json_serialized_packet_data() { let json = to_byte_array(PACKET_DATA_FROM_SN(ERC20())); let expected: ByteArray = - "{\"denom\":\"2087021424722619777119509474943472645767659996348769578120564519014510906823\",\"amount\":\"100\",\"sender\":\"340767163730\",\"receiver\":\"cosmos1wxeyh7zgn4tctjzs0vtqpc6p5cxq5t2muzl7ng\",\"memo\":\"\"}"; + "{\"denom\":\"2087021424722619777119509474943472645767659996348769578120564519014510906823\",\"amount\":\"100\",\"sender\":\"1431520594\",\"receiver\":\"cosmos1wxeyh7zgn4tctjzs0vtqpc6p5cxq5t2muzl7ng\",\"memo\":\"\"}"; assert_eq!(json, expected); } diff --git a/cairo-contracts/packages/contracts/src/tests/channel.cairo b/cairo-contracts/packages/contracts/src/tests/channel.cairo index a302d4ba..853f5a05 100644 --- a/cairo-contracts/packages/contracts/src/tests/channel.cairo +++ b/cairo-contracts/packages/contracts/src/tests/channel.cairo @@ -1,3 +1,4 @@ +use snforge_std::start_cheat_caller_address; use starknet_ibc_apps::transfer::{ERC20Contract, SUCCESS_ACK, VERSION}; use starknet_ibc_core::channel::{ChannelEndTrait, ChannelOrdering, AckStatus, ChannelState}; use starknet_ibc_core::client::{Height, Timestamp}; @@ -6,8 +7,8 @@ use starknet_ibc_testkit::configs::{ TransferAppConfigTrait, CoreConfigTrait, CometClientConfigTrait }; use starknet_ibc_testkit::dummies::{ - OWNER, HEIGHT, TIMESTAMP, COSMOS, STARKNET, CLIENT_ID, CONNECTION_ID, CHANNEL_ID, PORT_ID, - SUPPLY, PACKET_COMMITMENT_ON_SN, RELAYER + HEIGHT, TIMESTAMP, COSMOS, STARKNET, CLIENT_ID, CONNECTION_ID, CHANNEL_ID, PORT_ID, SUPPLY, + PACKET_COMMITMENT_ON_SN, RELAYER, SN_USER, CS_USER }; use starknet_ibc_testkit::event_spy::{TransferEventSpyExt, ChannelEventSpyExt}; use starknet_ibc_testkit::handles::{CoreHandle, AppHandle, ERC20Handle}; @@ -206,7 +207,7 @@ fn test_recv_packet_ok() { // Assert the `RecvEvent` emitted by the ICS20 contract. spy .assert_recv_event( - ics20.address, COSMOS(), STARKNET(), prefixed_denom.clone(), transfer_cfg.amount, true + ics20.address, CS_USER(), SN_USER(), prefixed_denom.clone(), transfer_cfg.amount, true ); // Assert the `ReceivePacketEvent` emitted by the core contract. @@ -218,7 +219,7 @@ fn test_recv_packet_ok() { let erc20: ERC20Contract = token_address.into(); // Check the balance of the receiver. - erc20.assert_balance(OWNER(), transfer_cfg.amount); + erc20.assert_balance(SN_USER(), transfer_cfg.amount); // Check the total supply of the ERC20 contract. erc20.assert_total_supply(transfer_cfg.amount); @@ -251,11 +252,13 @@ fn test_successful_ack_packet_ok() { // Send Packet (from Starknet to Cosmos) // ----------------------------------------------------------- - // Owner approves the amount of allowance for the `TransferApp` contract. - erc20.approve(OWNER(), ics20.address, transfer_cfg.amount); + start_cheat_caller_address(ics20.address, SN_USER()); + + // User approves the amount of allowance for the `TransferApp` contract. + erc20.approve(SN_USER(), ics20.address, transfer_cfg.amount); let msg_transfer = transfer_cfg - .dummy_msg_transfer(transfer_cfg.native_denom.clone(), STARKNET(), COSMOS()); + .dummy_msg_transfer(transfer_cfg.native_denom.clone(), CS_USER()); // Submit a `MsgTransfer` to the `TransferApp` contract. ics20.send_transfer(msg_transfer.clone()); @@ -277,12 +280,14 @@ fn test_successful_ack_packet_ok() { assert_eq!(commitment, PACKET_COMMITMENT_ON_SN(erc20)); // Check the balance of the sender. - erc20.assert_balance(OWNER(), SUPPLY - transfer_cfg.amount); + erc20.assert_balance(SN_USER(), SUPPLY - transfer_cfg.amount); // ----------------------------------------------------------- // Acknowledge Packet (on Starknet) // ----------------------------------------------------------- + start_cheat_caller_address(ics20.address, core.address); + let msg = transfer_cfg .dummy_msg_ack_packet( transfer_cfg.native_denom.clone(), STARKNET(), COSMOS(), SUCCESS_ACK() @@ -297,8 +302,8 @@ fn test_successful_ack_packet_ok() { spy .assert_ack_event( ics20.address, - STARKNET(), - COSMOS(), + SN_USER(), + CS_USER(), transfer_cfg.native_denom.clone(), transfer_cfg.amount, SUCCESS_ACK() @@ -309,7 +314,7 @@ fn test_successful_ack_packet_ok() { spy.assert_ack_packet_event(core.address, ChannelOrdering::Unordered, msg.packet.clone()); // Check the balance of the sender. - erc20.assert_balance(OWNER(), SUPPLY - transfer_cfg.amount); + erc20.assert_balance(SN_USER(), SUPPLY - transfer_cfg.amount); core .packet_commitment( @@ -330,11 +335,13 @@ fn test_failure_ack_packet_ok() { // Send Packet (from Starknet to Cosmos) // ----------------------------------------------------------- - // Owner approves the amount of allowance for the `TransferApp` contract. - erc20.approve(OWNER(), ics20.address, transfer_cfg.amount); + start_cheat_caller_address(ics20.address, SN_USER()); + + // User approves the amount of allowance for the `TransferApp` contract. + erc20.approve(SN_USER(), ics20.address, transfer_cfg.amount); let msg_transfer = transfer_cfg - .dummy_msg_transfer(transfer_cfg.native_denom.clone(), STARKNET(), COSMOS()); + .dummy_msg_transfer(transfer_cfg.native_denom.clone(), CS_USER()); // Submit a `MsgTransfer` to the `TransferApp` contract. ics20.send_transfer(msg_transfer.clone()); @@ -356,12 +363,14 @@ fn test_failure_ack_packet_ok() { assert_eq!(commitment, PACKET_COMMITMENT_ON_SN(erc20)); // Check the balance of the sender. - erc20.assert_balance(OWNER(), SUPPLY - transfer_cfg.amount); + erc20.assert_balance(SN_USER(), SUPPLY - transfer_cfg.amount); // ----------------------------------------------------------- // Acknowledge Packet (on Starknet) // ----------------------------------------------------------- + start_cheat_caller_address(ics20.address, core.address); + let failure_ack = array![0].into(); let msg = transfer_cfg @@ -378,8 +387,8 @@ fn test_failure_ack_packet_ok() { spy .assert_ack_event( ics20.address, - STARKNET(), - COSMOS(), + SN_USER(), + CS_USER(), transfer_cfg.native_denom.clone(), transfer_cfg.amount, failure_ack.clone() @@ -390,7 +399,7 @@ fn test_failure_ack_packet_ok() { spy.assert_ack_packet_event(core.address, ChannelOrdering::Unordered, msg.packet.clone()); // Check if the balance of the sender to ensure the refund. - erc20.assert_balance(OWNER(), SUPPLY); + erc20.assert_balance(SN_USER(), SUPPLY); core .packet_commitment( @@ -442,10 +451,12 @@ fn try_timeout_packet(timeout_height: Height, timeout_timestamp: Timestamp) { // Send Packet (from Starknet to Cosmos) // ----------------------------------------------------------- - erc20.approve(OWNER(), ics20.address, transfer_cfg.amount); + start_cheat_caller_address(ics20.address, SN_USER()); + + erc20.approve(SN_USER(), ics20.address, transfer_cfg.amount); let msg_transfer = transfer_cfg - .dummy_msg_transfer(transfer_cfg.native_denom.clone(), STARKNET(), COSMOS()); + .dummy_msg_transfer(transfer_cfg.native_denom.clone(), CS_USER()); ics20.send_transfer(msg_transfer.clone()); @@ -453,6 +464,8 @@ fn try_timeout_packet(timeout_height: Height, timeout_timestamp: Timestamp) { // Update Client // ----------------------------------------------------------- + start_cheat_caller_address(ics20.address, core.address); + core.register_relayer(RELAYER()); let msg = comet_cfg @@ -482,7 +495,7 @@ fn try_timeout_packet(timeout_height: Height, timeout_timestamp: Timestamp) { spy.assert_timeout_packet_event(core.address, ChannelOrdering::Unordered, packet.clone()); // Check if the balance of the sender to ensure the refund. - erc20.assert_balance(OWNER(), SUPPLY); + erc20.assert_balance(SN_USER(), SUPPLY); core .packet_commitment( diff --git a/cairo-contracts/packages/contracts/src/tests/transfer.cairo b/cairo-contracts/packages/contracts/src/tests/transfer.cairo index cc50e023..88f3b5b2 100644 --- a/cairo-contracts/packages/contracts/src/tests/transfer.cairo +++ b/cairo-contracts/packages/contracts/src/tests/transfer.cairo @@ -1,6 +1,7 @@ +use snforge_std::start_cheat_caller_address; use starknet_ibc_apps::transfer::ERC20Contract; use starknet_ibc_testkit::configs::TransferAppConfigTrait; -use starknet_ibc_testkit::dummies::{NAME, SYMBOL, SUPPLY, OWNER, COSMOS, STARKNET}; +use starknet_ibc_testkit::dummies::{NAME, SYMBOL, SUPPLY, COSMOS, STARKNET, SN_USER, CS_USER}; use starknet_ibc_testkit::event_spy::TransferEventSpyExt; use starknet_ibc_testkit::handles::{AppHandle, CoreHandle, ERC20Handle}; use starknet_ibc_testkit::setup::{setup, Mode}; @@ -18,11 +19,13 @@ fn test_escrow_unescrow_roundtrip() { // Escrow // ----------------------------------------------------------- - // Owner approves the amount of allowance for the `TransferApp` contract. - erc20.approve(OWNER(), ics20.address, transfer_cfg.amount); + start_cheat_caller_address(ics20.address, SN_USER()); + + // User approves the amount of allowance for the `TransferApp` contract. + erc20.approve(SN_USER(), ics20.address, transfer_cfg.amount); let msg_transfer = transfer_cfg - .dummy_msg_transfer(transfer_cfg.native_denom.clone(), STARKNET(), COSMOS()); + .dummy_msg_transfer(transfer_cfg.native_denom.clone(), CS_USER()); // Submit a `MsgTransfer` to the `TransferApp` contract. ics20.send_transfer(msg_transfer); @@ -31,14 +34,14 @@ fn test_escrow_unescrow_roundtrip() { spy .assert_send_event( ics20.address, - STARKNET(), - COSMOS(), + SN_USER(), + CS_USER(), transfer_cfg.native_denom.clone(), transfer_cfg.amount ); // Check the balance of the sender. - erc20.assert_balance(OWNER(), SUPPLY - transfer_cfg.amount); + erc20.assert_balance(SN_USER(), SUPPLY - transfer_cfg.amount); // Check the balance of the `TransferApp` contract. erc20.assert_balance(ics20.address, transfer_cfg.amount); @@ -47,6 +50,8 @@ fn test_escrow_unescrow_roundtrip() { // Unescrow // ----------------------------------------------------------- + start_cheat_caller_address(ics20.address, core.address); + let prefixed_denom = transfer_cfg.prefix_native_denom(); let msg_recv_packet = transfer_cfg @@ -57,13 +62,13 @@ fn test_escrow_unescrow_roundtrip() { // Assert the `RecvEvent` emitted. spy .assert_recv_event( - ics20.address, COSMOS(), STARKNET(), prefixed_denom, transfer_cfg.amount, true + ics20.address, CS_USER(), SN_USER(), prefixed_denom, transfer_cfg.amount, true ); erc20.assert_balance(ics20.address, 0); // Check the balance of the recipient. - erc20.assert_balance(OWNER(), SUPPLY); + erc20.assert_balance(SN_USER(), SUPPLY); } #[test] @@ -97,13 +102,13 @@ fn test_mint_burn_roundtrip() { // Assert the `RecvEvent` emitted. spy .assert_recv_event( - ics20.address, COSMOS(), STARKNET(), prefixed_denom.clone(), transfer_cfg.amount, true + ics20.address, CS_USER(), SN_USER(), prefixed_denom.clone(), transfer_cfg.amount, true ); let erc20: ERC20Contract = token_address.into(); // Check the balance of the receiver. - erc20.assert_balance(OWNER(), transfer_cfg.amount); + erc20.assert_balance(SN_USER(), transfer_cfg.amount); // Check the total supply of the ERC20 contract. erc20.assert_total_supply(transfer_cfg.amount); @@ -112,17 +117,18 @@ fn test_mint_burn_roundtrip() { // Burn // ----------------------------------------------------------- - let msg_transfer = transfer_cfg - .dummy_msg_transfer(prefixed_denom.clone(), STARKNET(), COSMOS()); + start_cheat_caller_address(ics20.address, SN_USER()); + + let msg_transfer = transfer_cfg.dummy_msg_transfer(prefixed_denom.clone(), CS_USER()); - // Owner approves the amount of allowance for the `TransferApp` contract. + // User approves the amount of allowance for the `TransferApp` contract. ics20.send_transfer(msg_transfer); // Assert the `SendEvent` emitted. - spy.assert_send_event(ics20.address, STARKNET(), COSMOS(), prefixed_denom, transfer_cfg.amount); + spy.assert_send_event(ics20.address, SN_USER(), CS_USER(), prefixed_denom, transfer_cfg.amount); // Check the balance of the sender. - erc20.assert_balance(OWNER(), 0); + erc20.assert_balance(SN_USER(), 0); // Check the balance of the `TransferApp` contract. erc20.assert_balance(ics20.address, 0); diff --git a/cairo-contracts/packages/core/src/tests/commitment.cairo b/cairo-contracts/packages/core/src/tests/commitment.cairo index 0a8c49e5..d785731f 100644 --- a/cairo-contracts/packages/core/src/tests/commitment.cairo +++ b/cairo-contracts/packages/core/src/tests/commitment.cairo @@ -52,7 +52,7 @@ fn test_array_u8_into_array_u32() { fn test_compute_packet_commitment() { let commitment = PACKET_COMMITMENT_ON_SN(ERC20()); let expected: [u32; 8] = [ - 921559061, 1448239305, 530172570, 2261752703, 2027737158, 303675019, 1363635866, 3548973031 + 3458244073, 1576048754, 4210798310, 1002247062, 2365181318, 2763927782, 545147151, 944653547 ]; assert_eq!(commitment, expected.into()); } diff --git a/cairo-contracts/packages/testkit/src/configs/transfer.cairo b/cairo-contracts/packages/testkit/src/configs/transfer.cairo index de668f12..f64c7712 100644 --- a/cairo-contracts/packages/testkit/src/configs/transfer.cairo +++ b/cairo-contracts/packages/testkit/src/configs/transfer.cairo @@ -74,12 +74,15 @@ pub impl TransferAppConfigImpl of TransferAppConfigTrait { } fn dummy_msg_transfer( - self: @TransferAppConfig, denom: PrefixedDenom, sender: Participant, receiver: Participant + self: @TransferAppConfig, denom: PrefixedDenom, receiver: ByteArray ) -> MsgTransfer { MsgTransfer { port_id_on_a: PORT_ID(), chan_id_on_a: self.chan_id_on_a.clone(), - packet_data: self.dummy_packet_data(denom, sender, receiver), + denom, + amount: *self.amount, + receiver, + memo: EMPTY_MEMO(), timeout_height_on_b: self.timeout_height.clone(), timeout_timestamp_on_b: self.timeout_timestamp.clone(), } diff --git a/cairo-contracts/packages/testkit/src/dummies/transfer.cairo b/cairo-contracts/packages/testkit/src/dummies/transfer.cairo index 92933928..bed144aa 100644 --- a/cairo-contracts/packages/testkit/src/dummies/transfer.cairo +++ b/cairo-contracts/packages/testkit/src/dummies/transfer.cairo @@ -19,10 +19,6 @@ pub fn SYMBOL() -> ByteArray { "IBC/UATOM" } -pub fn OWNER() -> ContractAddress { - contract_address_const::<'OWNER'>() -} - pub fn CLASS_HASH() -> ClassHash { class_hash_const::<'ERC20Mintable'>() } @@ -32,13 +28,24 @@ pub fn ERC20() -> ERC20Contract { .into() } +pub fn OWNER() -> ContractAddress { + contract_address_const::<'OWNER'>() +} + +pub fn SN_USER() -> ContractAddress { + contract_address_const::<'USER'>() +} + +pub fn CS_USER() -> ByteArray { + "cosmos1wxeyh7zgn4tctjzs0vtqpc6p5cxq5t2muzl7ng" +} + pub fn STARKNET() -> Participant { - OWNER().into() + SN_USER().into() } pub fn COSMOS() -> Participant { - let bech32_address: ByteArray = "cosmos1wxeyh7zgn4tctjzs0vtqpc6p5cxq5t2muzl7ng"; - bech32_address.into() + CS_USER().into() } pub fn NATIVE_DENOM() -> PrefixedDenom { diff --git a/cairo-contracts/packages/testkit/src/event_spy/transfer.cairo b/cairo-contracts/packages/testkit/src/event_spy/transfer.cairo index 3bf7110a..b0df7f38 100644 --- a/cairo-contracts/packages/testkit/src/event_spy/transfer.cairo +++ b/cairo-contracts/packages/testkit/src/event_spy/transfer.cairo @@ -4,7 +4,7 @@ use starknet::ContractAddress; use starknet_ibc_apps::transfer::TokenTransferComponent::{ Event, SendEvent, RecvEvent, AckEvent, AckStatusEvent, CreateTokenEvent }; -use starknet_ibc_apps::transfer::types::{Participant, PrefixedDenom}; +use starknet_ibc_apps::transfer::types::PrefixedDenom; use starknet_ibc_core::channel::{Acknowledgement, AckStatus}; use starknet_ibc_testkit::dummies::EMPTY_MEMO; @@ -13,8 +13,8 @@ pub impl TransferEventSpyExtImpl of TransferEventSpyExt { fn assert_send_event( ref self: EventSpy, contract_address: ContractAddress, - sender: Participant, - receiver: Participant, + sender: ContractAddress, + receiver: ByteArray, denom: PrefixedDenom, amount: u256 ) { @@ -27,8 +27,8 @@ pub impl TransferEventSpyExtImpl of TransferEventSpyExt { fn assert_recv_event( ref self: EventSpy, contract_address: ContractAddress, - sender: Participant, - receiver: Participant, + sender: ByteArray, + receiver: ContractAddress, denom: PrefixedDenom, amount: u256, success: bool @@ -42,8 +42,8 @@ pub impl TransferEventSpyExtImpl of TransferEventSpyExt { fn assert_ack_event( ref self: EventSpy, contract_address: ContractAddress, - sender: Participant, - receiver: Participant, + sender: ContractAddress, + receiver: ByteArray, denom: PrefixedDenom, amount: u256, ack: Acknowledgement diff --git a/cairo-contracts/packages/testkit/src/handles/erc20.cairo b/cairo-contracts/packages/testkit/src/handles/erc20.cairo index 960d0d4e..359b9491 100644 --- a/cairo-contracts/packages/testkit/src/handles/erc20.cairo +++ b/cairo-contracts/packages/testkit/src/handles/erc20.cairo @@ -3,7 +3,7 @@ use openzeppelin_token::erc20::ERC20ABIDispatcherTrait; use snforge_std::{ContractClass, start_cheat_caller_address}; use starknet::ContractAddress; use starknet_ibc_apps::transfer::{ERC20Contract, ERC20ContractTrait}; -use starknet_ibc_testkit::dummies::{NAME, SYMBOL, SUPPLY, OWNER}; +use starknet_ibc_testkit::dummies::{NAME, SYMBOL, SUPPLY, OWNER, SN_USER}; #[generate_trait] pub impl ERC20HandleImpl of ERC20Handle { @@ -35,7 +35,7 @@ pub(crate) fn dummy_erc20_call_data() -> Array { Serde::serialize(@NAME(), ref call_data); Serde::serialize(@SYMBOL(), ref call_data); Serde::serialize(@SUPPLY, ref call_data); - Serde::serialize(@OWNER(), ref call_data); + Serde::serialize(@SN_USER(), ref call_data); Serde::serialize(@OWNER(), ref call_data); call_data } diff --git a/cairo-contracts/packages/testkit/src/lib.cairo b/cairo-contracts/packages/testkit/src/lib.cairo index a9794367..d16ae9ba 100644 --- a/cairo-contracts/packages/testkit/src/lib.cairo +++ b/cairo-contracts/packages/testkit/src/lib.cairo @@ -33,8 +33,9 @@ pub mod dummies { STATE_PROOF, STATE_ROOT, IBC_PREFIX, RELAYER }; pub use transfer::{ - NAME, SYMBOL, ERC20, AMOUNT, SUPPLY, OWNER, STARKNET, COSMOS, NATIVE_DENOM, HOSTED_DENOM, - SALT, DECIMALS, CLASS_HASH, EMPTY_MEMO, PACKET_DATA_FROM_SN, PACKET_COMMITMENT_ON_SN + NAME, SYMBOL, ERC20, AMOUNT, SUPPLY, OWNER, SN_USER, CS_USER, STARKNET, COSMOS, + NATIVE_DENOM, HOSTED_DENOM, SALT, DECIMALS, CLASS_HASH, EMPTY_MEMO, PACKET_DATA_FROM_SN, + PACKET_COMMITMENT_ON_SN }; } pub mod event_spy { diff --git a/cairo-contracts/packages/testkit/src/mocks/transfer.cairo b/cairo-contracts/packages/testkit/src/mocks/transfer.cairo index eecbfc6d..6a7b0802 100644 --- a/cairo-contracts/packages/testkit/src/mocks/transfer.cairo +++ b/cairo-contracts/packages/testkit/src/mocks/transfer.cairo @@ -2,8 +2,7 @@ pub mod MockTransferApp { use core::num::traits::Zero; use openzeppelin_access::ownable::OwnableComponent; - use starknet::ClassHash; - use starknet::ContractAddress; + use starknet::{ClassHash, ContractAddress, get_caller_address}; use starknet_ibc_apps::transfer::ERC20Contract; use starknet_ibc_apps::transfer::types::{PrefixedDenom, Memo, MsgTransfer}; use starknet_ibc_apps::transfer::{ @@ -73,8 +72,9 @@ pub mod MockTransferApp { #[external(v0)] fn send_transfer_internal(ref self: ContractState, msg: MsgTransfer) { - self.transfer.send_validate(msg.clone()); - self.transfer.send_execute(msg); + let sender = get_caller_address(); + self.transfer.send_validate(msg.clone(), sender); + self.transfer.send_execute(msg, sender); } #[external(v0)] diff --git a/relayer/crates/starknet-chain-components/src/types/events/ics20.rs b/relayer/crates/starknet-chain-components/src/types/events/ics20.rs index 103d55cf..6798ec10 100644 --- a/relayer/crates/starknet-chain-components/src/types/events/ics20.rs +++ b/relayer/crates/starknet-chain-components/src/types/events/ics20.rs @@ -9,7 +9,6 @@ use starknet::macros::selector; use crate::types::event::{StarknetEvent, UnknownEvent}; use crate::types::messages::ibc::denom::PrefixedDenom; -use crate::types::messages::ibc::ibc_transfer::Participant; use crate::types::messages::ibc::packet::{AckStatus, Acknowledgement}; #[derive(Debug)] @@ -24,8 +23,8 @@ pub enum IbcTransferEvent { #[derive(Debug)] pub struct SendIbcTransferEvent { - pub sender: Participant, - pub receiver: Participant, + pub sender: Felt, + pub receiver: String, pub denom: PrefixedDenom, pub amount: U256, pub memo: String, @@ -33,8 +32,8 @@ pub struct SendIbcTransferEvent { #[derive(Debug)] pub struct ReceiveIbcTransferEvent { - pub sender: Participant, - pub receiver: Participant, + pub sender: String, + pub receiver: Felt, pub denom: PrefixedDenom, pub amount: U256, pub memo: String, @@ -43,8 +42,8 @@ pub struct ReceiveIbcTransferEvent { #[derive(Debug)] pub struct AckIbcTransferEvent { - pub sender: Participant, - pub receiver: Participant, + pub sender: Felt, + pub receiver: String, pub denom: PrefixedDenom, pub amount: U256, @@ -59,9 +58,8 @@ pub struct AckStatusIbcTransferEvent { #[derive(Debug)] pub struct TimeoutIbcTransferEvent { - pub receiver: Participant, + pub receiver: String, pub denom: PrefixedDenom, - pub amount: U256, pub memo: String, } @@ -120,7 +118,7 @@ where + HasEncoding + CanRaiseAsyncError, CairoEncoding: HasEncodedType> - + CanDecode + + CanDecode + CanDecode, { fn decode( @@ -154,7 +152,7 @@ where + HasEncoding + CanRaiseAsyncError, CairoEncoding: HasEncodedType> - + CanDecode + + CanDecode + CanDecode, { fn decode( @@ -189,7 +187,7 @@ where + HasEncoding + CanRaiseAsyncError, CairoEncoding: HasEncodedType> - + CanDecode + + CanDecode + CanDecode, { fn decode( @@ -251,7 +249,7 @@ where + HasEncoding + CanRaiseAsyncError, CairoEncoding: HasEncodedType> - + CanDecode + + CanDecode + CanDecode, { fn decode( diff --git a/relayer/crates/starknet-chain-components/src/types/messages/ibc/ibc_transfer.rs b/relayer/crates/starknet-chain-components/src/types/messages/ibc/ibc_transfer.rs index ae7e00ed..ff816a2c 100644 --- a/relayer/crates/starknet-chain-components/src/types/messages/ibc/ibc_transfer.rs +++ b/relayer/crates/starknet-chain-components/src/types/messages/ibc/ibc_transfer.rs @@ -64,7 +64,10 @@ impl Transformer for EncodeTransferPacketData { pub struct MsgTransfer { pub port_id_on_a: PortId, pub chan_id_on_a: ChannelId, - pub packet_data: TransferPacketData, + pub denom: PrefixedDenom, + pub amount: U256, + pub receiver: String, + pub memo: String, pub timeout_height_on_b: Height, pub timeout_timestamp_on_b: Timestamp, } @@ -77,7 +80,10 @@ delegate_components! { Product![ EncodeField, EncodeField, - EncodeField, + EncodeField, + EncodeField, + EncodeField, + EncodeField, EncodeField, EncodeField, ], diff --git a/relayer/crates/starknet-integration-tests/src/tests/ics20.rs b/relayer/crates/starknet-integration-tests/src/tests/ics20.rs index 88453198..249db489 100644 --- a/relayer/crates/starknet-integration-tests/src/tests/ics20.rs +++ b/relayer/crates/starknet-integration-tests/src/tests/ics20.rs @@ -45,9 +45,7 @@ use hermes_starknet_chain_components::types::messages::ibc::channel::PortId; use hermes_starknet_chain_components::types::messages::ibc::denom::{ Denom, PrefixedDenom, TracePrefix, }; -use hermes_starknet_chain_components::types::messages::ibc::ibc_transfer::{ - MsgTransfer, Participant, TransferPacketData, -}; +use hermes_starknet_chain_components::types::messages::ibc::ibc_transfer::MsgTransfer; use hermes_starknet_chain_components::types::payloads::client::StarknetCreateClientPayloadOptions; use hermes_starknet_chain_components::types::register::{MsgRegisterApp, MsgRegisterClient}; use hermes_starknet_chain_context::contexts::chain::StarknetChain; @@ -526,9 +524,11 @@ fn test_starknet_ics20_contract() -> Result<(), Error> { assert_eq!(balance_starknet_b_step_1.quantity, transfer_quantity.into()); - // create ibc transfer packet data + // create ibc transfer message + + let starknet_ics20_send_message = { + let current_starknet_time = starknet_chain.query_chain_status().await?.time; - let starknet_ic20_packet_data = { let denom = PrefixedDenom { trace_path: vec![TracePrefix { port_id: ics20_port.to_string(), @@ -537,34 +537,15 @@ fn test_starknet_ics20_contract() -> Result<(), Error> { base: Denom::Hosted(denom_cosmos.to_string()), }; - let amount = transfer_quantity.into(); - - let sender = Participant::Native(*address_starknet_b); - - let receiver = Participant::External(address_cosmos_a.clone()); - - let memo = String::new(); - - TransferPacketData { - denom, - amount, - sender, - receiver, - memo, - } - }; - - // create ibc transfer message - - let starknet_ics20_send_message = { - let current_starknet_time = starknet_chain.query_chain_status().await?.time; - MsgTransfer { port_id_on_a: PortId { port_id: ics20_port.to_string(), }, chan_id_on_a: starknet_channel_id.clone(), - packet_data: starknet_ic20_packet_data, + denom, + amount: transfer_quantity.into(), + receiver: address_cosmos_a.clone(), + memo: String::new(), timeout_height_on_b: Height { revision_number: 0, revision_height: 0, @@ -642,40 +623,23 @@ fn test_starknet_ics20_contract() -> Result<(), Error> { // submit ics20 transfer from Starknet to Cosmos - let starknet_ic20_packet_data = { + let starknet_ics20_send_message = { + let current_starknet_time = starknet_chain.query_chain_status().await?.time; + let denom = PrefixedDenom { trace_path: vec![], base: Denom::Native(*erc20_token_address), }; - let amount = transfer_quantity.into(); - - let sender = Participant::Native(*address_starknet_b); - - let receiver = Participant::External(address_cosmos_a.clone()); - - let memo = String::new(); - - TransferPacketData { - denom, - amount, - sender, - receiver, - memo, - } - }; - - // create ibc transfer message - - let starknet_ics20_send_message = { - let current_starknet_time = starknet_chain.query_chain_status().await?.time; - MsgTransfer { port_id_on_a: PortId { port_id: ics20_port.to_string(), }, chan_id_on_a: starknet_channel_id.clone(), - packet_data: starknet_ic20_packet_data, + denom, + amount: transfer_quantity.into(), + receiver: address_cosmos_a.clone(), + memo: String::new(), timeout_height_on_b: Height { revision_number: 0, revision_height: 0,