diff --git a/cairo/src/contracts/token/libs/token_router.cairo b/cairo/src/contracts/token/libs/token_router.cairo index f7ba08b..d3abf91 100644 --- a/cairo/src/contracts/token/libs/token_router.cairo +++ b/cairo/src/contracts/token/libs/token_router.cairo @@ -1,91 +1,181 @@ +use alexandria_bytes::Bytes; +use starknet::ContractAddress; + #[starknet::interface] pub trait ITokenRouter { - fn initialize(ref self: TState); fn transfer_remote( - self: @TState, destination: u32, recipient: Array, amount_or_id: u256 - ) -> u256; - fn transfer_remote_with_hook( - self: @TState, + ref self: TState, destination: u32, - // TODO: make this fixed size once we switch to 2.7.0 - recipient: Array, + recipient: u256, amount_or_id: u256, - hook_metadata: u256, - hook: u256 + value: u256, + hook_metadata: Option, + hook: Option ) -> u256; - fn balance_of(self: @TState, account: u256) -> u256; } #[starknet::component] -pub mod TokenRouter { +pub mod TokenRouterComponent { + use alexandria_bytes::{Bytes, BytesTrait}; + use hyperlane_starknet::contracts::client::gas_router_component::{ + GasRouterComponent, GasRouterComponent::GasRouterInternalImpl + }; + use hyperlane_starknet::contracts::client::mailboxclient_component::{ + MailboxclientComponent, MailboxclientComponent::MailboxClientInternalImpl, + MailboxclientComponent::MailboxClient + }; + use hyperlane_starknet::contracts::client::router_component::{ + RouterComponent, RouterComponent::RouterComponentInternalImpl, IRouter, + }; + use hyperlane_starknet::contracts::token::libs::token_message::TokenMessageTrait; + use openzeppelin::access::ownable::{ + OwnableComponent, OwnableComponent::InternalImpl as OwnableInternalImpl + }; use starknet::ContractAddress; + #[storage] struct Storage {} - fn constructor() {} + #[event] + #[derive(Drop, starknet::Event)] + enum Event { + SentTransferRemote: SentTransferRemote, + ReceivedTransferRemote: ReceivedTransferRemote, + } - impl TokenRouterImpl< - TContractState, +HasComponent, - > of super::ITokenRouter> { - fn initialize(ref self: ComponentState) {} + #[derive(Drop, starknet::Event)] + pub struct SentTransferRemote { + pub destination: u32, + pub recipient: u256, + pub amount: u256, + } - fn transfer_remote( - self: @ComponentState, - destination: u32, - // TODO: make this fixed size once we switch to 2.7.0 - recipient: Array, - amount_or_id: u256 - ) -> u256 { - 0 - } + #[derive(Drop, starknet::Event)] + pub struct ReceivedTransferRemote { + pub origin: u32, + pub recipient: u256, + pub amount: u256, + } - fn transfer_remote_with_hook( - self: @ComponentState, + #[embeddable_as(TokenRouterImpl)] + impl TokenRouter< + TContractState, + +HasComponent, + +Drop, + impl MailBoxClient: MailboxclientComponent::HasComponent, + impl Router: RouterComponent::HasComponent, + impl Owner: OwnableComponent::HasComponent, + impl GasRouter: GasRouterComponent::HasComponent, + > of super::ITokenRouter> { + fn transfer_remote( + ref self: ComponentState, destination: u32, - // TODO: make this fixed size once we switch to 2.7.0 - recipient: Array, + recipient: u256, amount_or_id: u256, - hook_metadata: u256, - hook: u256 + value: u256, + hook_metadata: Option, + hook: Option ) -> u256 { - 0 - } - - fn balance_of(self: @ComponentState, account: u256) -> u256 { - 0 + match hook_metadata { + Option::Some(hook_metadata) => { + self + ._transfer_remote( + destination, + recipient, + amount_or_id, + value, + Option::Some(hook_metadata), + hook + ) + }, + Option::None => { + self + ._transfer_remote( + destination, recipient, amount_or_id, value, Option::None, Option::None + ) + } + } } } #[generate_trait] - impl InternalImpl< - TContractState, +HasComponent + pub impl TokenRouterInternalImpl< + TContractState, + +HasComponent, + +Drop, + impl MailBoxClient: MailboxclientComponent::HasComponent, + impl Router: RouterComponent::HasComponent, + impl Owner: OwnableComponent::HasComponent, + impl GasRouter: GasRouterComponent::HasComponent, > of InternalTrait { + fn initialize(ref self: ComponentState, mailbox: ContractAddress) { + let mut gas_router_comp = get_dep_component_mut!(ref self, GasRouter); + gas_router_comp.initialize(mailbox); + } + fn _transfer_remote( ref self: ComponentState, destination: u32, - // TODO: make this fixed size once we switch to 2.7.0 - recipient: Array, + recipient: u256, amount_or_id: u256, value: u256, - hook_metadata: Option>, + hook_metadata: Option, hook: Option ) -> u256 { - 0 + let token_metadata = self._transfer_from_sender(amount_or_id); + let token_message = TokenMessageTrait::format(recipient, amount_or_id, token_metadata); + + let mut router_comp = get_dep_component!(@self, Router); + let mailbox_comp = get_dep_component!(@self, MailBoxClient); + let gas_router_comp = get_dep_component!(@self, GasRouter); + + let mut message_id = 0; + + match hook_metadata { + Option::Some(hook_metadata) => { + if !hook.is_some() { + panic!("Transfer remote invalid arguments, missing hook"); + } + + message_id = router_comp + ._Router_dispatch( + destination, value, token_message, hook_metadata, hook.unwrap() + ); + }, + Option::None => { + let hook_metadata = gas_router_comp._Gas_router_hook_metadata(destination); + let hook = mailbox_comp.get_hook(); + message_id = router_comp + ._Router_dispatch(destination, value, token_message, hook_metadata, hook); + } + } + + self.emit(SentTransferRemote { destination, recipient, amount: amount_or_id, }); + + message_id } fn _transfer_from_sender( ref self: ComponentState, amount_or_id: u256 - ) -> u256 { - 0 + ) -> Bytes { + BytesTrait::new_empty() } - fn _handle(ref self: ComponentState, origin: u32, message: u256) {} + fn _handle(ref self: ComponentState, origin: u32, message: Bytes) { + let recipient = message.recipient(); + let amount = message.amount(); + let metadata = message.metadata(); + + self._transfer_to(recipient, amount, metadata); + + self.emit(ReceivedTransferRemote { origin, recipient, amount, }); + } fn _transfer_to( ref self: ComponentState, - recipient: ContractAddress, + recipient: u256, amount_or_id: u256, - metadata: Array + metadata: Bytes ) {} } }