diff --git a/cairo/crates/contracts/src/client/mailboxclient_component.cairo b/cairo/crates/contracts/src/client/mailboxclient_component.cairo index d8b2f69b..bb57e573 100644 --- a/cairo/crates/contracts/src/client/mailboxclient_component.cairo +++ b/cairo/crates/contracts/src/client/mailboxclient_component.cairo @@ -18,6 +18,7 @@ pub mod MailboxclientComponent { pub mod Errors { pub const ADDRESS_CANNOT_BE_ZERO: felt252 = 'Address cannot be zero'; + pub const CALLER_NOT_MAILBOX: felt252 = 'Caller not mailbox'; } #[embeddable_as(MailboxClientImpl)] @@ -117,71 +118,6 @@ pub mod MailboxclientComponent { let mailbox: IMailboxDispatcher = self.mailbox.read(); mailbox.contract_address } - - /// Dispatches a message to the destination domain & recipient. - /// - /// # Arguments - /// - /// * - `_destination_domain` Domain of destination chain - /// * - `_recipient` Address of recipient on destination chain - /// * - `_message_body` Bytes content of message body - /// * - `_fee_amount` - the payment provided for sending the message - /// * - `_hook_metadata` Metadata used by the post dispatch hook - /// * - `_hook` Custom hook to use instead of the default - /// - /// # Returns - /// - /// u256 - The message ID inserted into the Mailbox's merkle tree - fn _dispatch( - self: @ComponentState, - _destination_domain: u32, - _recipient: u256, - _message_body: Bytes, - _fee_amount: u256, - _hook_metadata: Option, - _hook: Option - ) -> u256 { - self - .mailbox - .read() - .dispatch( - _destination_domain, - _recipient, - _message_body, - _fee_amount, - _hook_metadata, - _hook - ) - } - - /// Computes quote for dispatching a message to the destination domain & recipient. - /// - /// # Arguments - /// - /// * - `_destination_domain` Domain of destination chain - /// * - `_recipient` Address of recipient on destination chain - /// * - `_message_body` Bytes content of message body - /// * - `_hook_metadata` Metadata used by the post dispatch hook - /// * - `_hook` Custom hook to use instead of the default - /// - /// # Returns - /// - /// u256 - The payment required to dispatch the message - fn quote_dispatch( - self: @ComponentState, - _destination_domain: u32, - _recipient: u256, - _message_body: Bytes, - _hook_metadata: Option, - _hook: Option - ) -> u256 { - self - .mailbox - .read() - .quote_dispatch( - _destination_domain, _recipient, _message_body, _hook_metadata, _hook - ) - } } #[generate_trait] @@ -210,5 +146,15 @@ pub mod MailboxclientComponent { self.interchain_security_module.write(ism); } } + + /// Panics if caller is not the 'mailbox'. + /// Use this to restrict access to certain functions to the `mailbox`. + fn assert_only_mailbox(self: @ComponentState) { + let mailbox: IMailboxDispatcher = self.mailbox.read(); + assert( + starknet::get_caller_address() == mailbox.contract_address, + Errors::CALLER_NOT_MAILBOX + ); + } } } diff --git a/cairo/crates/contracts/src/client/router_component.cairo b/cairo/crates/contracts/src/client/router_component.cairo index cf4743f5..e1a7113c 100644 --- a/cairo/crates/contracts/src/client/router_component.cairo +++ b/cairo/crates/contracts/src/client/router_component.cairo @@ -26,23 +26,28 @@ pub mod RouterComponent { use contracts::client::mailboxclient_component::{ MailboxclientComponent, MailboxclientComponent::MailboxClientInternalImpl }; - use contracts::interfaces::{IMailboxClient, IMailboxDispatcher, IMailboxDispatcherTrait}; + use contracts::interfaces::{ + IMailboxClient, IMailboxDispatcher, IMailboxDispatcherTrait, ETH_ADDRESS + }; use contracts::libs::enumerable_map::{EnumerableMap, EnumerableMapTrait}; use openzeppelin::access::ownable::{ OwnableComponent, OwnableComponent::InternalImpl as OwnableInternalImpl }; + use openzeppelin::token::erc20::interface::{IERC20Dispatcher, IERC20DispatcherTrait}; use starknet::ContractAddress; #[storage] struct Storage { routers: EnumerableMap, - gas_router: ContractAddress, } mod Err { pub fn domain_not_found(domain: u32) { panic!("No router enrolled for domain {}", domain); } + pub fn fee_transfer_failed() { + panic!("fee transfer from sender failed"); + } } pub trait IMessageRecipientInternalHookTrait { @@ -55,7 +60,7 @@ pub mod RouterComponent { pub impl Router< TContractState, +HasComponent, - +MailboxclientComponent::HasComponent, + impl MailboxClient: MailboxclientComponent::HasComponent, impl Owner: OwnableComponent::HasComponent, +Drop, impl Hook: IMessageRecipientInternalHookTrait @@ -132,7 +137,9 @@ pub mod RouterComponent { /// # Arguments /// /// * `domains` - An array of `u32` values representing the domains for which routers are being unenrolled. - fn unenroll_remote_routers(ref self: ComponentState, domains: Array,) { + fn unenroll_remote_routers(ref self: ComponentState, domains: Array) { + let ownable_comp = get_dep_component!(@self, Owner); + ownable_comp.assert_only_owner(); let domains_len = domains.len(); let mut i = 0; while i < domains_len { @@ -159,6 +166,8 @@ pub mod RouterComponent { fn handle( ref self: ComponentState, origin: u32, sender: u256, message: Bytes ) { + let mailbox_client_comp = get_dep_component!(@self, MailboxClient); + mailbox_client_comp.assert_only_mailbox(); let router = self._must_have_remote_router(origin); assert!(router == sender, "Enrolled router does not match sender"); @@ -242,9 +251,19 @@ pub mod RouterComponent { ) -> u256 { let router = self._must_have_remote_router(destination_domain); let mut mailbox_comp = get_dep_component!(self, MailBoxClient); - let value = mailbox_comp - .mailbox - .read() + + let mut fee_token_dispatcher = IERC20Dispatcher { contract_address: ETH_ADDRESS() }; + if !fee_token_dispatcher + .transfer_from( + starknet::get_caller_address(), starknet::get_contract_address(), value + ) { + Err::fee_transfer_failed(); + } + + let mailbox_dispatcher = mailbox_comp.mailbox.read(); + fee_token_dispatcher.approve(mailbox_dispatcher.contract_address, value); + + let value = mailbox_dispatcher .dispatch( destination_domain, router, diff --git a/cairo/crates/contracts/src/interfaces.cairo b/cairo/crates/contracts/src/interfaces.cairo index cd3c68ee..e5d2d338 100644 --- a/cairo/crates/contracts/src/interfaces.cairo +++ b/cairo/crates/contracts/src/interfaces.cairo @@ -156,25 +156,6 @@ pub trait IMailboxClient { fn _is_delivered(self: @TContractState, _id: u256) -> bool; fn mailbox(self: @TContractState) -> ContractAddress; - - fn _dispatch( - self: @TContractState, - _destination_domain: u32, - _recipient: u256, - _message_body: Bytes, - _fee_amount: u256, - _hook_metadata: Option, - _hook: Option - ) -> u256; - - fn quote_dispatch( - self: @TContractState, - _destination_domain: u32, - _recipient: u256, - _message_body: Bytes, - _hook_metadata: Option, - _hook: Option - ) -> u256; } diff --git a/cairo/crates/mocks/src/erc4626_component.cairo b/cairo/crates/mocks/src/erc4626_component.cairo index 26c9391b..d194c07c 100644 --- a/cairo/crates/mocks/src/erc4626_component.cairo +++ b/cairo/crates/mocks/src/erc4626_component.cairo @@ -60,6 +60,8 @@ pub mod ERC4626Component { pub const EXCEEDED_MAX_MINT: felt252 = 'ERC4626: exceeded max mint'; pub const EXCEEDED_MAX_REDEEM: felt252 = 'ERC4626: exceeded max redeem'; pub const EXCEEDED_MAX_WITHDRAW: felt252 = 'ERC4626: exceeded max withdraw'; + pub const ERC20_TRANSFER_FAILED: felt252 = 'ERC20 transfer failed'; + pub const ERC20_TRANSFER_FROM_FAILED: felt252 = 'ERC20 transfer_from failed'; } pub trait ERC4626HooksTrait { @@ -442,7 +444,10 @@ pub mod ERC4626Component { Hooks::before_deposit(ref self, caller, receiver, assets, shares); let dispatcher = ERC20ABIDispatcher { contract_address: self.ERC4626_asset.read() }; - dispatcher.transfer_from(caller, get_contract_address(), assets); + assert( + dispatcher.transfer_from(caller, get_contract_address(), assets), + Errors::ERC20_TRANSFER_FROM_FAILED + ); let mut erc20_comp_mut = get_dep_component_mut!(ref self, ERC20); erc20_comp_mut.mint(receiver, shares); self.emit(Deposit { sender: caller, owner: receiver, assets, shares }); @@ -473,7 +478,7 @@ pub mod ERC4626Component { erc20_comp_mut.burn(owner, shares); let dispatcher = ERC20ABIDispatcher { contract_address: self.ERC4626_asset.read() }; - dispatcher.transfer(receiver, assets); + assert(dispatcher.transfer(receiver, assets), Errors::ERC20_TRANSFER_FAILED); self.emit(Withdraw { sender: caller, receiver, owner, assets, shares }); diff --git a/cairo/crates/token/src/components/fast_token_router.cairo b/cairo/crates/token/src/components/fast_token_router.cairo index 96d9d848..a74a8690 100644 --- a/cairo/crates/token/src/components/fast_token_router.cairo +++ b/cairo/crates/token/src/components/fast_token_router.cairo @@ -29,18 +29,14 @@ pub mod FastTokenRouterComponent { MailboxclientComponent::MailboxClient }; use contracts::client::router_component::{ - RouterComponent, RouterComponent::RouterComponentInternalImpl, - RouterComponent::IMessageRecipientInternalHookTrait, IRouter + RouterComponent, RouterComponent::IMessageRecipientInternalHookTrait }; use contracts::utils::utils::U256TryIntoContractAddress; - use openzeppelin::access::ownable::{ - OwnableComponent, OwnableComponent::InternalImpl as OwnableInternalImpl - }; + use openzeppelin::access::ownable::OwnableComponent; use starknet::ContractAddress; use token::components::token_message::TokenMessageTrait; use token::components::token_router::{ - TokenRouterComponent, TokenRouterComponent::TokenRouterInternalImpl, - TokenRouterComponent::TokenRouterHooksTrait + TokenRouterComponent, TokenRouterComponent::TokenRouterHooksTrait }; #[storage] @@ -237,7 +233,7 @@ pub mod FastTokenRouterComponent { let filler_address = self ._get_fast_transfers_key(origin, fast_transfer_id, amount, fast_fee, recipient); - if filler_address == 0 { + if filler_address != 0 { return filler_address; } diff --git a/cairo/crates/token/src/components/hyp_erc20_collateral_component.cairo b/cairo/crates/token/src/components/hyp_erc20_collateral_component.cairo index c4c2ea70..6128d31a 100644 --- a/cairo/crates/token/src/components/hyp_erc20_collateral_component.cairo +++ b/cairo/crates/token/src/components/hyp_erc20_collateral_component.cairo @@ -9,27 +9,16 @@ pub trait IHypErc20Collateral { #[starknet::component] pub mod HypErc20CollateralComponent { use alexandria_bytes::{Bytes, BytesTrait}; - use contracts::client::gas_router_component::{ - GasRouterComponent, - GasRouterComponent::{GasRouterInternalImpl, InternalTrait as GasRouterInternalTrait} + use contracts::client::{ + gas_router_component::GasRouterComponent, router_component::RouterComponent, + mailboxclient_component::MailboxclientComponent }; - use contracts::client::mailboxclient_component::{ - MailboxclientComponent, MailboxclientComponent::MailboxClientImpl - }; - use contracts::client::router_component::{ - RouterComponent, - RouterComponent::{InternalTrait as RouterInternalTrait, RouterComponentInternalImpl} - }; - use contracts::interfaces::IMailboxClient; - use contracts::utils::utils::{U256TryIntoContractAddress}; - + use contracts::utils::utils::U256TryIntoContractAddress; use openzeppelin::access::ownable::OwnableComponent; use openzeppelin::token::erc20::{ERC20ABIDispatcher, ERC20ABIDispatcherTrait}; use starknet::ContractAddress; - use token::components::token_message::TokenMessageTrait; use token::components::token_router::{ - TokenRouterComponent, TokenRouterComponent::TokenRouterInternalImpl, - TokenRouterComponent::TokenRouterHooksTrait + TokenRouterComponent, TokenRouterComponent::TokenRouterHooksTrait }; #[storage] @@ -37,6 +26,11 @@ pub mod HypErc20CollateralComponent { wrapped_token: ERC20ABIDispatcher } + pub mod Errors { + pub const ERC20_TRANSFER_FAILED: felt252 = 'ERC20 transfer failed'; + pub const ERC20_TRANSFER_FROM_FAILED: felt252 = 'ERC20 transfer_from failed'; + } + pub impl TokenRouterHooksImpl< TContractState, +HasComponent, @@ -123,20 +117,28 @@ pub mod HypErc20CollateralComponent { } fn _transfer_from_sender(ref self: ComponentState, amount: u256) -> Bytes { - self - .wrapped_token - .read() - .transfer_from( - starknet::get_caller_address(), starknet::get_contract_address(), amount - ); + assert( + self + .wrapped_token + .read() + .transfer_from( + starknet::get_caller_address(), starknet::get_contract_address(), amount + ), + Errors::ERC20_TRANSFER_FROM_FAILED + ); BytesTrait::new_empty() } fn _transfer_to(ref self: ComponentState, recipient: u256, amount: u256) { - self - .wrapped_token - .read() - .transfer(recipient.try_into().expect('u256 to ContractAddress failed'), amount); + assert( + self + .wrapped_token + .read() + .transfer( + recipient.try_into().expect('u256 to ContractAddress failed'), amount + ), + Errors::ERC20_TRANSFER_FAILED + ); } } } diff --git a/cairo/crates/token/src/components/hyp_erc20_component.cairo b/cairo/crates/token/src/components/hyp_erc20_component.cairo index 9f9fd658..9495e153 100644 --- a/cairo/crates/token/src/components/hyp_erc20_component.cairo +++ b/cairo/crates/token/src/components/hyp_erc20_component.cairo @@ -1,21 +1,11 @@ -use starknet::ContractAddress; - #[starknet::component] pub mod HypErc20Component { use alexandria_bytes::{Bytes, BytesTrait}; - use contracts::client::gas_router_component::{ - GasRouterComponent, - GasRouterComponent::{GasRouterInternalImpl, InternalTrait as GasRouterInternalTrait} - }; - use contracts::client::mailboxclient_component::{ - MailboxclientComponent, MailboxclientComponent::MailboxClientImpl - }; - use contracts::client::router_component::{ - RouterComponent, - RouterComponent::{InternalTrait as RouterInternalTrait, RouterComponentInternalImpl} + use contracts::client::{ + gas_router_component::GasRouterComponent, router_component::RouterComponent, + mailboxclient_component::MailboxclientComponent }; - use contracts::interfaces::IMailboxClient; - use contracts::utils::utils::{U256TryIntoContractAddress}; + use contracts::utils::utils::U256TryIntoContractAddress; use openzeppelin::access::ownable::OwnableComponent; use openzeppelin::token::erc20::ERC20Component; use openzeppelin::token::erc20::{ @@ -24,10 +14,8 @@ pub mod HypErc20Component { }; use starknet::ContractAddress; - use token::components::token_message::TokenMessageTrait; use token::components::token_router::{ - TokenRouterComponent, TokenRouterComponent::TokenRouterInternalImpl, - TokenRouterComponent::TokenRouterHooksTrait + TokenRouterComponent, TokenRouterComponent::TokenRouterHooksTrait }; #[storage] diff --git a/cairo/crates/token/src/components/hyp_erc721_collateral_component.cairo b/cairo/crates/token/src/components/hyp_erc721_collateral_component.cairo index b93b51a3..764e0290 100644 --- a/cairo/crates/token/src/components/hyp_erc721_collateral_component.cairo +++ b/cairo/crates/token/src/components/hyp_erc721_collateral_component.cairo @@ -10,15 +10,16 @@ pub trait IHypErc721Collateral { #[starknet::component] pub mod HypErc721CollateralComponent { use alexandria_bytes::{Bytes, BytesTrait}; - use contracts::client::mailboxclient_component::{ - MailboxclientComponent, MailboxclientComponent::MailboxClientInternalImpl, - MailboxclientComponent::MailboxClient - }; - use openzeppelin::access::ownable::{ - OwnableComponent, OwnableComponent::InternalImpl, OwnableComponent::OwnableImpl + use contracts::client::{ + gas_router_component::GasRouterComponent, router_component::RouterComponent, + mailboxclient_component::MailboxclientComponent }; + use openzeppelin::access::ownable::OwnableComponent; use openzeppelin::token::erc721::interface::{ERC721ABIDispatcher, ERC721ABIDispatcherTrait}; use starknet::ContractAddress; + use token::components::token_router::{ + TokenRouterComponent, TokenRouterComponent::TokenRouterHooksTrait + }; #[storage] struct Storage { @@ -78,4 +79,67 @@ pub mod HypErc721CollateralComponent { wrapped_token.contract_address } } + + pub impl TokenRouterHooksImpl< + TContractState, + +HasComponent, + +Drop, + +MailboxclientComponent::HasComponent, + +RouterComponent::HasComponent, + +OwnableComponent::HasComponent, + +GasRouterComponent::HasComponent, + +TokenRouterComponent::HasComponent, + > of TokenRouterHooksTrait { + fn transfer_from_sender_hook( + ref self: TokenRouterComponent::ComponentState, amount_or_id: u256 + ) -> Bytes { + let mut contract_state = TokenRouterComponent::HasComponent::get_contract_mut(ref self); + let mut component_state = HasComponent::get_component_mut(ref contract_state); + + component_state + .wrapped_token + .read() + .transfer_from( + starknet::get_caller_address(), starknet::get_contract_address(), amount_or_id + ); + + BytesTrait::new_empty() + } + + fn transfer_to_hook( + ref self: TokenRouterComponent::ComponentState, + recipient: u256, + amount_or_id: u256, + metadata: Bytes + ) { + let mut contract_state = TokenRouterComponent::HasComponent::get_contract_mut(ref self); + let mut component_state = HasComponent::get_component_mut(ref contract_state); + + let recipient_felt: felt252 = recipient.try_into().expect('u256 to felt failed'); + let recipient: ContractAddress = recipient_felt.try_into().unwrap(); + + let metadata_array_u128 = metadata.data(); + let mut metadata_array_felt252: Array = array![]; + + let len = metadata_array_u128.len(); + let mut i = 0; + while i < len { + let metadata_felt252: felt252 = (*metadata_array_u128.at(i)) + .try_into() + .expect('u128 to felt failed'); + metadata_array_felt252.append(metadata_felt252); + i = i + 1; + }; + + component_state + .wrapped_token + .read() + .safe_transfer_from( + starknet::get_contract_address(), + recipient, + amount_or_id, + metadata_array_felt252.span() + ); + } + } } diff --git a/cairo/crates/token/src/components/hyp_erc721_component.cairo b/cairo/crates/token/src/components/hyp_erc721_component.cairo index a3de8957..a1486de0 100644 --- a/cairo/crates/token/src/components/hyp_erc721_component.cairo +++ b/cairo/crates/token/src/components/hyp_erc721_component.cairo @@ -5,16 +5,9 @@ pub trait IHypErc721 { #[starknet::component] pub mod HypErc721Component { - use contracts::client::mailboxclient_component::{ - MailboxclientComponent, MailboxclientComponent::MailboxClientInternalImpl, - MailboxclientComponent::MailboxClient - }; - use openzeppelin::access::ownable::{ - OwnableComponent, OwnableComponent::InternalImpl as OwnableInternalImpl - }; - use openzeppelin::introspection::src5::{ - SRC5Component, SRC5Component::SRC5Impl, SRC5Component::InternalTrait as SRC5InternalTrait - }; + use contracts::client::mailboxclient_component::{MailboxclientComponent}; + use openzeppelin::access::ownable::OwnableComponent; + use openzeppelin::introspection::src5::{SRC5Component, SRC5Component::SRC5Impl}; use openzeppelin::token::erc721::{ ERC721Component, ERC721Component::ERC721Impl, ERC721Component::InternalTrait as ERC721InternalTrait, ERC721Component::ERC721HooksTrait, diff --git a/cairo/crates/token/src/components/hyp_native_component.cairo b/cairo/crates/token/src/components/hyp_native_component.cairo index 11a6e98f..1a65300f 100644 --- a/cairo/crates/token/src/components/hyp_native_component.cairo +++ b/cairo/crates/token/src/components/hyp_native_component.cairo @@ -2,43 +2,27 @@ use starknet::ContractAddress; #[starknet::interface] pub trait IHypNative { - // fn balance_of(self: @TState, account: ContractAddress) -> u256; fn receive(ref self: TState, amount: u256); } #[starknet::component] pub mod HypNativeComponent { use alexandria_bytes::{Bytes, BytesTrait}; - use contracts::client::gas_router_component::{ - GasRouterComponent, - GasRouterComponent::{GasRouterInternalImpl, InternalTrait as GasRouterInternalTrait} - }; - use contracts::client::mailboxclient_component::{ - MailboxclientComponent, MailboxclientComponent::MailboxClientImpl - }; - use contracts::client::router_component::{ - RouterComponent, - RouterComponent::{InternalTrait as RouterInternalTrait, RouterComponentInternalImpl} - }; - use openzeppelin::access::ownable::{ - OwnableComponent, OwnableComponent::InternalImpl, OwnableComponent::OwnableImpl - }; - use openzeppelin::token::erc20::{ - interface::{IERC20, ERC20ABIDispatcher, ERC20ABIDispatcherTrait}, ERC20Component + use contracts::client::{ + gas_router_component::GasRouterComponent, router_component::RouterComponent, + mailboxclient_component::MailboxclientComponent }; + use openzeppelin::access::ownable::OwnableComponent; + use openzeppelin::token::erc20::interface::{ERC20ABIDispatcher, ERC20ABIDispatcherTrait}; use starknet::ContractAddress; - use token::components::token_message::TokenMessageTrait; use token::components::token_router::{ - TokenRouterComponent, TokenRouterComponent::TokenRouterInternalImpl, - TokenRouterComponent::TokenRouterHooksTrait, ITokenRouter, + TokenRouterComponent, TokenRouterComponent::TokenRouterHooksTrait, ITokenRouter, TokenRouterTransferRemoteHookDefaultImpl }; - use token::interfaces::imessage_recipient::IMessageRecipient; - #[storage] struct Storage { - eth_token: ERC20ABIDispatcher, + native_token: ERC20ABIDispatcher, } #[event] @@ -53,6 +37,11 @@ pub mod HypNativeComponent { amount: u256, } + pub mod Errors { + pub const NATIVE_TOKEN_TRANSFER_FAILED: felt252 = 'Native token transfer failed'; + pub const NATIVE_TOKEN_TRANSFER_FROM_FAILED: felt252 = 'Native transfer_from failed'; + } + #[embeddable_as(HypNativeImpl)] impl HypNative< TContractState, @@ -61,12 +50,19 @@ pub mod HypNativeComponent { +OwnableComponent::HasComponent, +RouterComponent::HasComponent, +GasRouterComponent::HasComponent, - +ERC20Component::HasComponent, impl Mailboxclient: MailboxclientComponent::HasComponent, impl TokenRouter: TokenRouterComponent::HasComponent, > of super::IHypNative> { fn receive(ref self: ComponentState, amount: u256) { - self.eth_token.read().transfer(starknet::get_contract_address(), amount); + assert( + self + .native_token + .read() + .transfer_from( + starknet::get_caller_address(), starknet::get_contract_address(), amount + ), + Errors::NATIVE_TOKEN_TRANSFER_FROM_FAILED + ); self.emit(Donation { sender: starknet::get_caller_address(), amount }); } @@ -81,7 +77,6 @@ pub mod HypNativeComponent { +OwnableComponent::HasComponent, +GasRouterComponent::HasComponent, +TokenRouterComponent::HasComponent, - +ERC20Component::HasComponent > of TokenRouterHooksTrait { fn transfer_from_sender_hook( ref self: TokenRouterComponent::ComponentState, amount_or_id: u256 @@ -113,7 +108,6 @@ pub mod HypNativeComponent { +OwnableComponent::HasComponent, impl GasRouter: GasRouterComponent::HasComponent, impl TokenRouterComp: TokenRouterComponent::HasComponent, - impl ERC20: ERC20Component::HasComponent > of ITokenRouter> { fn transfer_remote( ref self: ComponentState, @@ -148,20 +142,33 @@ pub mod HypNativeComponent { +OwnableComponent::HasComponent, +RouterComponent::HasComponent, +GasRouterComponent::HasComponent, - +ERC20Component::HasComponent, impl Mailboxclient: MailboxclientComponent::HasComponent, impl TokenRouter: TokenRouterComponent::HasComponent, > of InternalTrait { + fn initialize(ref self: ComponentState, native_token: ContractAddress) { + self.native_token.write(ERC20ABIDispatcher { contract_address: native_token }); + } + fn _transfer_from_sender(ref self: ComponentState, amount: u256) -> Bytes { + assert( + self + .native_token + .read() + .transfer_from( + starknet::get_caller_address(), starknet::get_contract_address(), amount + ), + Errors::NATIVE_TOKEN_TRANSFER_FROM_FAILED + ); BytesTrait::new_empty() } fn _transfer_to(ref self: ComponentState, recipient: u256, amount: u256) { - let contract_address = starknet::get_contract_address(); // this address or eth address - let erc20_dispatcher = ERC20ABIDispatcher { contract_address }; let recipient_felt: felt252 = recipient.try_into().expect('u256 to felt failed'); let recipient: ContractAddress = recipient_felt.try_into().unwrap(); - erc20_dispatcher.transfer(recipient, amount); + assert( + self.native_token.read().transfer(recipient, amount), + Errors::NATIVE_TOKEN_TRANSFER_FAILED + ); } } } diff --git a/cairo/crates/token/src/components/token_router.cairo b/cairo/crates/token/src/components/token_router.cairo index 091ba64f..9a390db9 100644 --- a/cairo/crates/token/src/components/token_router.cairo +++ b/cairo/crates/token/src/components/token_router.cairo @@ -225,23 +225,6 @@ pub mod TokenRouterComponent { } } -//pub impl TokenRouterEmptyHooksImpl< -// TContractState -//> of TokenRouterComponent::TokenRouterHooksTrait { -// fn transfer_from_sender_hook( -// ref self: TokenRouterComponent::ComponentState, amount_or_id: u256 -// ) -> Bytes { -// alexandria_bytes::BytesTrait::new_empty() -// } -// -// fn transfer_to_hook( -// ref self: TokenRouterComponent::ComponentState, -// recipient: u256, -// amount_or_id: u256, -// metadata: Bytes -// ) {} -//} - pub impl TokenRouterTransferRemoteHookDefaultImpl< TContractState, +Drop, diff --git a/cairo/crates/token/src/extensions/fast_hyp_erc20_collateral.cairo b/cairo/crates/token/src/extensions/fast_hyp_erc20_collateral.cairo index 29d2d763..68ccf412 100644 --- a/cairo/crates/token/src/extensions/fast_hyp_erc20_collateral.cairo +++ b/cairo/crates/token/src/extensions/fast_hyp_erc20_collateral.cairo @@ -180,11 +180,16 @@ pub mod FastHypERC20Collateral { let mut contract_state = FastTokenRouterComponent::HasComponent::get_contract_mut( ref self ); - contract_state - .collateral - .wrapped_token - .read() - .transfer(recipient.try_into().expect('u256 to ContractAddress failed'), amount); + assert( + contract_state + .collateral + .wrapped_token + .read() + .transfer( + recipient.try_into().expect('u256 to ContractAddress failed'), amount + ), + 'ERC20 transfer failed' + ); } /// Receives tokens from the sender as part of the fast token router process. @@ -204,11 +209,14 @@ pub mod FastHypERC20Collateral { let mut contract_state = FastTokenRouterComponent::HasComponent::get_contract_mut( ref self ); - contract_state - .collateral - .wrapped_token - .read() - .transfer_from(sender, starknet::get_contract_address(), amount); + assert( + contract_state + .collateral + .wrapped_token + .read() + .transfer_from(sender, starknet::get_contract_address(), amount), + 'ERC20 transfer_from failed' + ); } } } diff --git a/cairo/crates/token/src/extensions/hyp_erc721_URI_collateral.cairo b/cairo/crates/token/src/extensions/hyp_erc721_URI_collateral.cairo index 725156e8..7e026b3f 100644 --- a/cairo/crates/token/src/extensions/hyp_erc721_URI_collateral.cairo +++ b/cairo/crates/token/src/extensions/hyp_erc721_URI_collateral.cairo @@ -65,8 +65,6 @@ pub mod HypERC721URICollateral { #[storage] struct Storage { - erc721: ContractAddress, - mailbox: ContractAddress, #[substorage(v0)] ownable: OwnableComponent::Storage, #[substorage(v0)] @@ -164,6 +162,10 @@ pub mod HypERC721URICollateral { recipient: u256, amount_or_id: u256, metadata: Bytes - ) {} + ) { + HypErc721CollateralComponent::TokenRouterHooksImpl::transfer_to_hook( + ref self, recipient, amount_or_id, metadata + ); + } } } diff --git a/cairo/crates/token/src/extensions/hyp_native_scaled.cairo b/cairo/crates/token/src/extensions/hyp_native_scaled.cairo index 41fd4fb2..958c7265 100644 --- a/cairo/crates/token/src/extensions/hyp_native_scaled.cairo +++ b/cairo/crates/token/src/extensions/hyp_native_scaled.cairo @@ -10,15 +10,11 @@ pub mod HypNativeScaled { use contracts::client::mailboxclient_component::MailboxclientComponent; use contracts::client::router_component::RouterComponent; use openzeppelin::access::ownable::OwnableComponent; - use openzeppelin::token::erc20::{ - interface::{ERC20ABIDispatcher, ERC20ABIDispatcherTrait}, ERC20Component, - ERC20HooksEmptyImpl - }; + use openzeppelin::token::erc20::interface::{ERC20ABIDispatcher, ERC20ABIDispatcherTrait}; use openzeppelin::upgrades::interface::IUpgradeable; use openzeppelin::upgrades::upgradeable::UpgradeableComponent; use starknet::ContractAddress; - use token::components::hyp_native_component::{HypNativeComponent}; - use token::components::token_message::TokenMessageTrait; + use token::components::hyp_native_component::HypNativeComponent; use token::components::token_router::{ TokenRouterComponent, ITokenRouter, TokenRouterComponent::TokenRouterHooksTrait, TokenRouterComponent::MessageRecipientInternalHookImpl, @@ -32,11 +28,7 @@ pub mod HypNativeScaled { component!(path: GasRouterComponent, storage: gas_router, event: GasRouterEvent); component!(path: HypNativeComponent, storage: hyp_native, event: HypNativeEvent); component!(path: UpgradeableComponent, storage: upgradeable, event: UpgradeableEvent); - component!(path: ERC20Component, storage: erc20, event: ERC20Event); - // ERC20 - #[abi(embed_v0)] - impl ERC20Impl = ERC20Component::ERC20MixinImpl; // Ownable #[abi(embed_v0)] impl OwnableImpl = OwnableComponent::OwnableImpl; @@ -44,9 +36,6 @@ pub mod HypNativeScaled { // HypNative #[abi(embed_v0)] impl HypNativeImpl = HypNativeComponent::HypNativeImpl; - #[abi(embed_v0)] - impl HypNativeTokenRouterImpl = - HypNativeComponent::TokenRouterImpl; impl HypNativeInternalImpl = HypNativeComponent::HypNativeInternalImpl; // GasRouter #[abi(embed_v0)] @@ -69,8 +58,6 @@ pub mod HypNativeScaled { struct Storage { scale: u256, #[substorage(v0)] - erc20: ERC20Component::Storage, - #[substorage(v0)] ownable: OwnableComponent::Storage, #[substorage(v0)] token_router: TokenRouterComponent::Storage, @@ -103,8 +90,6 @@ pub mod HypNativeScaled { HypNativeEvent: HypNativeComponent::Event, #[flat] UpgradeableEvent: UpgradeableComponent::Event, - #[flat] - ERC20Event: ERC20Component::Event, } #[constructor] @@ -135,7 +120,7 @@ pub mod HypNativeScaled { } } - #[embeddable_as(TokenRouterImpl)] + #[abi(embed_v0)] impl TokenRouter of ITokenRouter { fn transfer_remote( ref self: ContractState, @@ -164,7 +149,9 @@ pub mod HypNativeScaled { fn transfer_from_sender_hook( ref self: TokenRouterComponent::ComponentState, amount_or_id: u256 ) -> Bytes { - BytesTrait::new_empty() + let mut contract_state = TokenRouterComponent::HasComponent::get_contract_mut(ref self); + let amount_to_transfer = amount_or_id * contract_state.scale.read(); + contract_state.hyp_native._transfer_from_sender(amount_to_transfer) } fn transfer_to_hook( diff --git a/cairo/crates/token/src/hyp_erc721.cairo b/cairo/crates/token/src/hyp_erc721.cairo index 8f1f2122..b8e0b256 100644 --- a/cairo/crates/token/src/hyp_erc721.cairo +++ b/cairo/crates/token/src/hyp_erc721.cairo @@ -21,14 +21,13 @@ pub mod HypErc721 { use starknet::ContractAddress; use token::components::erc721_enumerable::ERC721EnumerableComponent; use token::components::hyp_erc721_component::HypErc721Component; - use token::components::token_message::TokenMessageTrait; use token::components::token_router::{ - TokenRouterComponent, ITokenRouter, TokenRouterComponent::TokenRouterHooksTrait, + TokenRouterComponent, TokenRouterComponent::TokenRouterHooksTrait, TokenRouterComponent::MessageRecipientInternalHookImpl, TokenRouterTransferRemoteHookDefaultImpl }; use token::interfaces::imessage_recipient::IMessageRecipient; - // also needs {https://github.com/OpenZeppelin/cairo-contracts/blob/main/packages/token/src/erc721/extensions/erc721_enumerable/erc721_enumerable.cairo} + component!(path: ERC721Component, storage: erc721, event: ERC721Event); component!(path: UpgradeableComponent, storage: upgradeable, event: UpgradeableEvent); component!(path: HypErc721Component, storage: hyp_erc721, event: HypErc721Event); @@ -50,7 +49,7 @@ pub mod HypErc721 { #[abi(embed_v0)] impl ERC721EnumerableImpl = ERC721EnumerableComponent::ERC721EnumerableImpl; - // impl ERC721EnumerableInternalImpl = ERC721EnumerableComponent::InternalImpl; + impl ERC721EnumerableInternalImpl = ERC721EnumerableComponent::InternalImpl; // Upgradeable impl UpgradeableInternalImpl = UpgradeableComponent::InternalImpl; @@ -149,6 +148,7 @@ pub mod HypErc721 { .mailboxclient .initialize(mailbox, Option::Some(hook), Option::Some(interchain_security_module)); self.hyp_erc721.initialize(mint_amount, name, symbol); + self.erc721_enumerable.initializer(); } #[abi(embed_v0)] diff --git a/cairo/crates/token/src/hyp_erc721_collateral.cairo b/cairo/crates/token/src/hyp_erc721_collateral.cairo index f6699585..cc82c0c2 100644 --- a/cairo/crates/token/src/hyp_erc721_collateral.cairo +++ b/cairo/crates/token/src/hyp_erc721_collateral.cairo @@ -9,11 +9,14 @@ pub mod HypErc721Collateral { use openzeppelin::upgrades::interface::IUpgradeable; use openzeppelin::upgrades::upgradeable::UpgradeableComponent; use starknet::ContractAddress; - use token::components::hyp_erc721_collateral_component::{HypErc721CollateralComponent}; - use token::components::token_router::{ - TokenRouterComponent, TokenRouterComponent::TokenRouterHooksTrait, - TokenRouterComponent::MessageRecipientInternalHookImpl, - TokenRouterTransferRemoteHookDefaultImpl + use token::components::{ + hyp_erc721_collateral_component::{ + HypErc721CollateralComponent, HypErc721CollateralComponent::TokenRouterHooksImpl + }, + token_router::{ + TokenRouterComponent, TokenRouterTransferRemoteHookDefaultImpl, + TokenRouterComponent::MessageRecipientInternalHookImpl, + } }; component!(path: OwnableComponent, storage: ownable, event: OwnableEvent); @@ -61,7 +64,6 @@ pub mod HypErc721Collateral { #[storage] struct Storage { - wrapped_token: ERC721ABIDispatcher, #[substorage(v0)] ownable: OwnableComponent::Storage, #[substorage(v0)] @@ -110,57 +112,10 @@ pub mod HypErc721Collateral { self .mailboxclient .initialize(mailbox, Option::Some(hook), Option::Some(interchain_security_module)); - self.wrapped_token.write(ERC721ABIDispatcher { contract_address: erc721 }); - } - - impl TokenRouterHooksImpl of TokenRouterHooksTrait { - fn transfer_from_sender_hook( - ref self: TokenRouterComponent::ComponentState, amount_or_id: u256 - ) -> Bytes { - let contract_state = TokenRouterComponent::HasComponent::get_contract(@self); - contract_state - .wrapped_token - .read() - .transfer_from( - starknet::get_caller_address(), starknet::get_contract_address(), amount_or_id - ); - - BytesTrait::new_empty() - } - - fn transfer_to_hook( - ref self: TokenRouterComponent::ComponentState, - recipient: u256, - amount_or_id: u256, - metadata: Bytes - ) { - let mut contract_state = TokenRouterComponent::HasComponent::get_contract_mut(ref self); - let recipient_felt: felt252 = recipient.try_into().expect('u256 to felt failed'); - let recipient: ContractAddress = recipient_felt.try_into().unwrap(); - - let metadata_array_u128 = metadata.data(); - let mut metadata_array_felt252: Array = array![]; - - let len = metadata_array_u128.len(); - let mut i = 0; - while i < len { - let metadata_felt252: felt252 = (*metadata_array_u128.at(i)) - .try_into() - .expect('u128 to felt failed'); - metadata_array_felt252.append(metadata_felt252); - i = i + 1; - }; - - contract_state - .wrapped_token - .read() - .safe_transfer_from( - starknet::get_contract_address(), - recipient, - amount_or_id, - metadata_array_felt252.span() - ); - } + self + .hyp_erc721_collateral + .wrapped_token + .write(ERC721ABIDispatcher { contract_address: erc721 }); } #[abi(embed_v0)] diff --git a/cairo/crates/token/src/hyp_native.cairo b/cairo/crates/token/src/hyp_native.cairo index ce546a18..48be0759 100644 --- a/cairo/crates/token/src/hyp_native.cairo +++ b/cairo/crates/token/src/hyp_native.cairo @@ -5,7 +5,6 @@ pub mod HypNative { use contracts::client::mailboxclient_component::MailboxclientComponent; use contracts::client::router_component::RouterComponent; use openzeppelin::access::ownable::OwnableComponent; - use openzeppelin::token::erc20::{ERC20Component, ERC20HooksEmptyImpl}; use openzeppelin::upgrades::interface::IUpgradeable; use openzeppelin::upgrades::upgradeable::UpgradeableComponent; use starknet::ContractAddress; @@ -23,7 +22,6 @@ pub mod HypNative { component!(path: RouterComponent, storage: router, event: RouterEvent); component!(path: GasRouterComponent, storage: gas_router, event: GasRouterEvent); component!(path: HypNativeComponent, storage: hyp_native, event: HypNativeEvent); - component!(path: ERC20Component, storage: erc20, event: ERC20Event); component!(path: UpgradeableComponent, storage: upgradeable, event: UpgradeableEvent); // HypNative @@ -53,9 +51,6 @@ pub mod HypNative { MailboxclientComponent::MailboxClientImpl; impl MailboxClientInternalImpl = MailboxclientComponent::MailboxClientInternalImpl; - // ERC20 - #[abi(embed_v0)] - impl ERC20MixinImpl = ERC20Component::ERC20MixinImpl; // Upgradeable impl UpgradeableInternalImpl = UpgradeableComponent::InternalImpl; @@ -74,8 +69,6 @@ pub mod HypNative { #[substorage(v0)] hyp_native: HypNativeComponent::Storage, #[substorage(v0)] - erc20: ERC20Component::Storage, - #[substorage(v0)] upgradeable: UpgradeableComponent::Storage } @@ -95,8 +88,6 @@ pub mod HypNative { #[flat] HypNativeEvent: HypNativeComponent::Event, #[flat] - ERC20Event: ERC20Component::Event, - #[flat] UpgradeableEvent: UpgradeableComponent::Event } @@ -104,6 +95,7 @@ pub mod HypNative { fn constructor( ref self: ContractState, mailbox: ContractAddress, + native_token: ContractAddress, hook: ContractAddress, interchain_security_module: ContractAddress, owner: ContractAddress @@ -112,6 +104,7 @@ pub mod HypNative { self .mailboxclient .initialize(mailbox, Option::Some(hook), Option::Some(interchain_security_module)); + self.hyp_native.initialize(native_token); } #[abi(embed_v0)] diff --git a/cairo/crates/token/tests/hyp_erc20/common.cairo b/cairo/crates/token/tests/hyp_erc20/common.cairo index 2ffed90c..f0d1c4f8 100644 --- a/cairo/crates/token/tests/hyp_erc20/common.cairo +++ b/cairo/crates/token/tests/hyp_erc20/common.cairo @@ -5,8 +5,10 @@ use contracts::client::gas_router_component::{ use contracts::client::router_component::{IRouterDispatcher, IRouterDispatcherTrait}; use contracts::interfaces::{ IMailboxDispatcher, IMailboxDispatcherTrait, IMessageRecipientDispatcher, - IMessageRecipientDispatcherTrait, IMailboxClientDispatcher, IMailboxClientDispatcherTrait + IMessageRecipientDispatcherTrait, IMailboxClientDispatcher, IMailboxClientDispatcherTrait, + ETH_ADDRESS }; +use core::integer::BoundedInt; use mocks::{ test_post_dispatch_hook::{ ITestPostDispatchHookDispatcher, ITestPostDispatchHookDispatcherTrait @@ -145,7 +147,7 @@ pub fn setup() -> Setup { let contract = declare("Ether").unwrap(); let mut calldata: Array = array![]; starknet::get_contract_address().serialize(ref calldata); - let (eth_address, _) = contract.deploy(@calldata).unwrap(); + let (eth_address, _) = contract.deploy_at(@calldata, ETH_ADDRESS()).unwrap(); let eth_token = MockEthDispatcher { contract_address: eth_address }; eth_token.mint(ALICE(), 10 * E18); @@ -205,6 +207,11 @@ pub fn setup() -> Setup { let (implementation, _) = hyp_erc20_contract.deploy(@calldata).unwrap(); let implementation = IHypERC20TestDispatcher { contract_address: implementation }; + start_prank(CheatTarget::One(eth_token.contract_address), ALICE()); + IERC20Dispatcher { contract_address: eth_token.contract_address } + .approve(implementation.contract_address, BoundedInt::max()); + stop_prank(CheatTarget::One(eth_token.contract_address)); + let contract = declare("TestInterchainGasPayment").unwrap(); let (igp, _) = contract.deploy(@array![]).unwrap(); let igp = ITestInterchainGasPaymentDispatcher { contract_address: igp }; @@ -234,6 +241,12 @@ pub fn setup() -> Setup { let local_token = IHypERC20TestDispatcher { contract_address: local_token }; let local_token_address: felt252 = local_token.contract_address.into(); + + start_prank(CheatTarget::One(eth_token.contract_address), ALICE()); + IERC20Dispatcher { contract_address: eth_token.contract_address } + .approve(local_token.contract_address, BoundedInt::max()); + stop_prank(CheatTarget::One(eth_token.contract_address)); + remote_token.enroll_remote_router(ORIGIN, local_token_address.into()); local_token.transfer(ALICE(), 1000 * E18); diff --git a/cairo/crates/token/tests/hyp_erc20/hyp_erc20_collateral_test.cairo b/cairo/crates/token/tests/hyp_erc20/hyp_erc20_collateral_test.cairo index 6239a7ba..8f21b7b6 100644 --- a/cairo/crates/token/tests/hyp_erc20/hyp_erc20_collateral_test.cairo +++ b/cairo/crates/token/tests/hyp_erc20/hyp_erc20_collateral_test.cairo @@ -3,6 +3,7 @@ use contracts::client::gas_router_component::{ GasRouterComponent::GasRouterConfig, IGasRouterDispatcher, IGasRouterDispatcherTrait }; use contracts::utils::utils::U256TryIntoContractAddress; +use core::integer::BoundedInt; use mocks::{ test_post_dispatch_hook::{ ITestPostDispatchHookDispatcher, ITestPostDispatchHookDispatcherTrait @@ -41,6 +42,11 @@ fn setup_hyp_erc20_collateral() -> (IHypERC20TestDispatcher, Setup) { let (collateral_address, _) = hyp_erc20_collateral_contract.deploy(@constructor_args).unwrap(); let collateral = IHypERC20TestDispatcher { contract_address: collateral_address }; + start_prank(CheatTarget::One(setup.eth_token.contract_address), ALICE()); + IERC20Dispatcher { contract_address: setup.eth_token.contract_address } + .approve(collateral_address, BoundedInt::max()); + stop_prank(CheatTarget::One(setup.eth_token.contract_address)); + // Enroll remote router let remote_token_address: felt252 = setup.remote_token.contract_address.into(); start_prank(CheatTarget::One(collateral.contract_address), ALICE()); diff --git a/cairo/crates/token/tests/hyp_erc20/hyp_erc20_lockbox_test.cairo b/cairo/crates/token/tests/hyp_erc20/hyp_erc20_lockbox_test.cairo index 33182d35..95138d0e 100644 --- a/cairo/crates/token/tests/hyp_erc20/hyp_erc20_lockbox_test.cairo +++ b/cairo/crates/token/tests/hyp_erc20/hyp_erc20_lockbox_test.cairo @@ -1,5 +1,6 @@ use alexandria_bytes::{Bytes, BytesTrait}; use contracts::client::gas_router_component::GasRouterComponent::GasRouterConfig; +use core::integer::BoundedInt; use mocks::test_interchain_gas_payment::ITestInterchainGasPaymentDispatcherTrait; use mocks::{ test_erc20::{ITestERC20Dispatcher, ITestERC20DispatcherTrait}, @@ -100,6 +101,13 @@ fn setup_lockbox() -> (Setup, IHypERC20LockboxTestDispatcher) { let (xerc20lockbox, _) = contract.deploy(@calldata).unwrap(); let xerc20lockbox = IHypERC20LockboxTestDispatcher { contract_address: xerc20lockbox }; + start_prank(CheatTarget::One(setup.eth_token.contract_address), ALICE()); + ERC20ABIDispatcher { contract_address: setup.eth_token.contract_address } + .approve(xerc20.contract_address, BoundedInt::max()); + ERC20ABIDispatcher { contract_address: setup.eth_token.contract_address } + .approve(lockbox.contract_address, BoundedInt::max()); + stop_prank(CheatTarget::One(setup.eth_token.contract_address)); + let remote_token_address: felt252 = setup.remote_token.contract_address.into(); xerc20lockbox.enroll_remote_router(DESTINATION, remote_token_address.into()); diff --git a/cairo/crates/token/tests/hyp_erc20/hyp_fiat_token_test.cairo b/cairo/crates/token/tests/hyp_erc20/hyp_fiat_token_test.cairo index ce3ea0e7..d42329db 100644 --- a/cairo/crates/token/tests/hyp_erc20/hyp_fiat_token_test.cairo +++ b/cairo/crates/token/tests/hyp_erc20/hyp_fiat_token_test.cairo @@ -1,3 +1,4 @@ +use core::integer::BoundedInt; use mocks::test_erc20::{ITestERC20Dispatcher, ITestERC20DispatcherTrait}; use mocks::test_interchain_gas_payment::ITestInterchainGasPaymentDispatcherTrait; use snforge_std::{ @@ -28,6 +29,11 @@ fn fiat_token_setup() -> Setup { let (fiat_token, _) = local_token.deploy(@calldata).unwrap(); let fiat_token = IHypERC20TestDispatcher { contract_address: fiat_token }; + start_prank(CheatTarget::One(setup.eth_token.contract_address), ALICE()); + ITestERC20Dispatcher { contract_address: setup.eth_token.contract_address } + .approve(fiat_token.contract_address, BoundedInt::max()); + stop_prank(CheatTarget::One(setup.eth_token.contract_address)); + let remote_token_address: felt252 = setup.remote_token.contract_address.into(); fiat_token.enroll_remote_router(DESTINATION, remote_token_address.into()); diff --git a/cairo/crates/token/tests/hyp_erc20/hyp_xerc20_test.cairo b/cairo/crates/token/tests/hyp_erc20/hyp_xerc20_test.cairo index 5f4fcabe..1a36fe11 100644 --- a/cairo/crates/token/tests/hyp_erc20/hyp_xerc20_test.cairo +++ b/cairo/crates/token/tests/hyp_erc20/hyp_xerc20_test.cairo @@ -1,3 +1,4 @@ +use core::integer::BoundedInt; use mocks::xerc20_test::{XERC20Test, IXERC20TestDispatcher, IXERC20TestDispatcherTrait}; use mocks::{test_erc20::{ITestERC20Dispatcher, ITestERC20DispatcherTrait},}; use snforge_std::{declare, ContractClassTrait, CheatTarget, start_prank, stop_prank,}; @@ -34,6 +35,11 @@ fn setup_xerc20() -> Setup { .unwrap(); setup.local_token = IHypERC20TestDispatcher { contract_address: local_token }; + start_prank(CheatTarget::One(setup.eth_token.contract_address), ALICE()); + ITestERC20Dispatcher { contract_address: setup.eth_token.contract_address } + .approve(local_token, BoundedInt::max()); + stop_prank(CheatTarget::One(setup.eth_token.contract_address)); + setup .local_token .enroll_remote_router( diff --git a/cairo/crates/token/tests/hyp_erc721/common.cairo b/cairo/crates/token/tests/hyp_erc721/common.cairo index 284497b9..cf1980fd 100644 --- a/cairo/crates/token/tests/hyp_erc721/common.cairo +++ b/cairo/crates/token/tests/hyp_erc721/common.cairo @@ -5,19 +5,22 @@ use contracts::client::gas_router_component::{ use contracts::client::router_component::{IRouterDispatcher, IRouterDispatcherTrait}; use contracts::interfaces::{ IMailboxDispatcher, IMailboxDispatcherTrait, IMessageRecipientDispatcher, - IMessageRecipientDispatcherTrait, IMailboxClientDispatcher, IMailboxClientDispatcherTrait + IMessageRecipientDispatcherTrait, IMailboxClientDispatcher, IMailboxClientDispatcherTrait, + ETH_ADDRESS }; +use core::integer::BoundedInt; use mocks::{ test_post_dispatch_hook::{ ITestPostDispatchHookDispatcher, ITestPostDispatchHookDispatcherTrait }, mock_mailbox::{IMockMailboxDispatcher, IMockMailboxDispatcherTrait}, - // test_erc721::{ITestERC721Dispatcher, ITestERC721DispatcherTrait}, test_interchain_gas_payment::{ ITestInterchainGasPaymentDispatcher, ITestInterchainGasPaymentDispatcherTrait }, - test_erc721::{ITestERC721Dispatcher, ITestERC721DispatcherTrait} + test_erc721::{ITestERC721Dispatcher, ITestERC721DispatcherTrait}, + mock_eth::{MockEthDispatcher, MockEthDispatcherTrait} }; +use openzeppelin::token::erc20::interface::{IERC20Dispatcher, IERC20DispatcherTrait}; use openzeppelin::token::erc721::interface::{IERC721Dispatcher, IERC721DispatcherTrait}; use snforge_std::cheatcodes::contract_class::ContractClass; use snforge_std::{ @@ -31,6 +34,7 @@ use token::components::hyp_erc721_collateral_component::{ use token::components::hyp_erc721_component::{IHypErc721Dispatcher, IHypErc721DispatcherTrait}; use token::components::token_router::{ITokenRouterDispatcher, ITokenRouterDispatcherTrait}; +pub const E18: u256 = 1_000_000_000_000_000_000; const PUB_KEY: felt252 = 0x1; const ZERO_SUPPLY: u256 = 0; pub fn ZERO_ADDRESS() -> ContractAddress { @@ -138,6 +142,7 @@ pub struct Setup { pub local_token: IHypErc721TestDispatcher, pub hyp_erc721_contract: ContractClass, pub hyp_erc721_collateral_contract: ContractClass, + pub eth_token: MockEthDispatcher, pub alice: ContractAddress, pub bob: ContractAddress, } @@ -162,9 +167,9 @@ pub fn setup() -> Setup { let contract = declare("Ether").unwrap(); let mut calldata: Array = array![]; starknet::get_contract_address().serialize(ref calldata); - let (eth_address, _) = contract.deploy(@calldata).unwrap(); - //let eth = MockEthDispatcher { contract_address: eth_address }; - + let (eth_address, _) = contract.deploy_at(@calldata, ETH_ADDRESS()).unwrap(); + let eth_token = MockEthDispatcher { contract_address: eth_address }; + eth_token.mint(starknet::get_contract_address(), 10 * E18); let contract = declare("MockMailbox").unwrap(); let (local_mailbox, _) = contract .deploy( @@ -207,6 +212,11 @@ pub fn setup() -> Setup { .unwrap(); let remote_token = IHypErc721TestDispatcher { contract_address: remote_token }; + start_prank(CheatTarget::One(eth_token.contract_address), ALICE()); + IERC20Dispatcher { contract_address: eth_token.contract_address } + .approve(remote_token.contract_address, BoundedInt::max()); + stop_prank(CheatTarget::One(eth_token.contract_address)); + let hyp_erc721_contract = declare("HypErc721").unwrap(); let mut calldata: Array = array![]; local_mailbox.contract_address.serialize(ref calldata); @@ -219,6 +229,11 @@ pub fn setup() -> Setup { let (local_token, _) = hyp_erc721_contract.deploy(@calldata).unwrap(); let local_token = IHypErc721TestDispatcher { contract_address: local_token }; + start_prank(CheatTarget::One(eth_token.contract_address), ALICE()); + IERC20Dispatcher { contract_address: eth_token.contract_address } + .approve(local_token.contract_address, BoundedInt::max()); + stop_prank(CheatTarget::One(eth_token.contract_address)); + let contract = declare("MockAccount").unwrap(); let (alice, _) = contract.deploy(@array![PUB_KEY]).unwrap(); let (bob, _) = contract.deploy(@array![PUB_KEY]).unwrap(); @@ -237,6 +252,7 @@ pub fn setup() -> Setup { local_token, hyp_erc721_contract, hyp_erc721_collateral_contract, + eth_token, alice, bob, } @@ -271,6 +287,10 @@ pub fn deploy_remote_token(mut setup: Setup, is_collateral: bool) -> Setup { } let local_token_address: felt252 = setup.local_token.contract_address.into(); setup.remote_token.enroll_remote_router(ORIGIN, local_token_address.into()); + + IERC20Dispatcher { contract_address: setup.eth_token.contract_address } + .approve(setup.local_token.contract_address, BoundedInt::max()); + setup } diff --git a/cairo/crates/token/tests/hyp_erc721/hyp_erc721_collateral_test.cairo b/cairo/crates/token/tests/hyp_erc721/hyp_erc721_collateral_test.cairo index 18ff8617..0ac594c5 100644 --- a/cairo/crates/token/tests/hyp_erc721/hyp_erc721_collateral_test.cairo +++ b/cairo/crates/token/tests/hyp_erc721/hyp_erc721_collateral_test.cairo @@ -1,6 +1,8 @@ use alexandria_bytes::Bytes; use contracts::client::router_component::{IRouterDispatcher, IRouterDispatcherTrait}; +use core::integer::BoundedInt; use mocks::test_erc721::{ITestERC721Dispatcher, ITestERC721DispatcherTrait}; +use openzeppelin::token::erc20::interface::{IERC20Dispatcher, IERC20DispatcherTrait}; use snforge_std::cheatcodes::contract_class::{ContractClass, ContractClassTrait}; use starknet::ContractAddress; use super::common::{ @@ -25,6 +27,9 @@ fn setup_erc721_collateral() -> Setup { setup.local_token = local_token; + IERC20Dispatcher { contract_address: setup.eth_token.contract_address } + .approve(local_token.contract_address, BoundedInt::max()); + let remote_token_address: felt252 = setup.remote_token.contract_address.into(); setup.local_token.enroll_remote_router(DESTINATION, remote_token_address.into());