module token_bridge::transfer_tokens { use sui::sui::SUI; use sui::coin::{Self, Coin, CoinMetadata}; use wormhole::state::{State as WormholeState}; use wormhole::external_address::{Self, ExternalAddress}; use wormhole::myu16::{Self as u16, U16}; use wormhole::emitter::{Self, EmitterCapability}; use token_bridge::bridge_state::{Self, BridgeState}; use token_bridge::transfer_result::{Self, TransferResult}; use token_bridge::transfer::{Self}; use token_bridge::normalized_amount::{Self}; use token_bridge::transfer_with_payload::{Self}; const E_TOO_MUCH_RELAYER_FEE: u64 = 0; public entry fun transfer_tokens( wormhole_state: &mut WormholeState, bridge_state: &mut BridgeState, coins: Coin, coin_metadata: &CoinMetadata, wormhole_fee_coins: Coin, recipient_chain: u64, recipient: vector, relayer_fee: u64, nonce: u64, ) { let result = transfer_tokens_internal( bridge_state, coins, coin_metadata, relayer_fee, ); let (token_chain, token_address, normalized_amount, normalized_relayer_fee) = transfer_result::destroy(result); let transfer = transfer::create( normalized_amount, token_address, token_chain, external_address::from_bytes(recipient), u16::from_u64(recipient_chain), normalized_relayer_fee, ); bridge_state::publish_message( wormhole_state, bridge_state, nonce, transfer::encode(transfer), wormhole_fee_coins, ); } public fun transfer_tokens_with_payload( emitter_cap: &EmitterCapability, wormhole_state: &mut WormholeState, bridge_state: &mut BridgeState, coins: Coin, coin_metadata: &CoinMetadata, wormhole_fee_coins: Coin, recipient_chain: U16, recipient: ExternalAddress, relayer_fee: u64, nonce: u64, payload: vector, ): u64 { let result = transfer_tokens_internal( bridge_state, coins, coin_metadata, relayer_fee, ); let (token_chain, token_address, normalized_amount, _) = transfer_result::destroy(result); let transfer = transfer_with_payload::create( normalized_amount, token_address, token_chain, recipient, recipient_chain, emitter::get_external_address(emitter_cap), payload ); let payload = transfer_with_payload::encode(transfer); bridge_state::publish_message( wormhole_state, bridge_state, nonce, payload, wormhole_fee_coins ) } fun transfer_tokens_internal( bridge_state: &mut BridgeState, coins: Coin, coin_metadata: &CoinMetadata, relayer_fee: u64, ): TransferResult { let amount = coin::value(&coins); assert!(relayer_fee <= amount, E_TOO_MUCH_RELAYER_FEE); if (bridge_state::is_wrapped_asset(bridge_state)) { // now we burn the wrapped coins to remove them from circulation bridge_state::burn(bridge_state, coins); } else { // deposit native assets. this call to deposit requires the native // asset to have been attested bridge_state::deposit(bridge_state, coins); }; let origin_info = bridge_state::origin_info(bridge_state); let token_chain = bridge_state::get_token_chain_from_origin_info(&origin_info); let token_address = bridge_state::get_token_address_from_origin_info(&origin_info); let decimals = coin::get_decimals(coin_metadata); let normalized_amount = normalized_amount::normalize(amount, decimals); let normalized_relayer_fee = normalized_amount::normalize(relayer_fee, decimals); let transfer_result: TransferResult = transfer_result::create( token_chain, token_address, normalized_amount, normalized_relayer_fee, ); transfer_result } }