This message is used to send coins from the sender's Bank module on Injective to the receiver's Bank module on another Cosmos chain through IBC, which is Cosmos's Inter-Blockchain Communication Protocol. Note that Injective only supports mainnet transfers across IBC for most networks.
Application to application communication in IBC is conducted over channels, which route between an application module on one chain, and the corresponding application module on another one. More info on IBC channels can be found at https://tutorials.cosmos.network/academy/3-ibc/3-channels.html. A list of canonical channel Ids for mainnet transfers to and from Injective can be found here. Also noteworthy is that the application module on each chain has a portId to designate the type of module on each end. For example, transfer is the portId designating the transfer of ICS-20 tokens between bank modules.
In this example, we will transfer ATOM from Injective to CosmosHub
import { ChainGrpcBankApi, ChainRestTendermintApi, makeTimeoutTimestampInNs, MsgBroadcasterWithPk, MsgTransfer,} from'@injectivelabs/sdk-ts'import { TokenService, UiBankTransformer, cosmosChainTokenMetaMap,} from'@injectivelabs/sdk-ui-ts'import { BigNumberInBase } from'@injectivelabs/utils'import { ChainId, CosmosChainId } from'@injectivelabs/ts-types'import { getNetworkEndpoints, Network } from'@injectivelabs/networks'import { IbcToken, Token } from'@injectivelabs/token-metadata'consttokenService=newTokenService({ chainId:ChainId.Mainnet, network:Network.Mainnet,})constdestinationChainId= CosmosChainId['Cosmoshub']constinjectiveChainId= CosmosChainId['Injective']constendpointsForNetwork=getNetworkEndpoints(Network.Mainnet)constbankService=newChainGrpcBankApi(endpointsForNetwork.grpc)// fetch ibc assets in bank module and format to tokenconst { supply } =awaitbankService.fetchTotalSupply()constuiSupply=UiBankTransformer.supplyToUiSupply(supply)constibcSupplyWithToken= (awaittokenService.getIbcSupplyWithToken(uiSupply.ibcBankSupply,)) asIbcToken[]/* get metadata for canonical denoms available for transfer between chains */constcosmosHubBaseDenom='uatom'consttokenMeta= cosmosChainTokenMetaMap[destinationChainId]constatomToken= (Array.isArray(tokenMeta)?tokenMeta.find((token) =>token.denom === cosmosHubBaseDenom): tokenMeta) asToken/* find the ibd denom hash for the canonical denom */constinjectiveToCosmosHubChannelId='channel-1'constatomDenomFromSupply=ibcSupplyWithToken.find( ({ channelId, baseDenom }) => channelId === injectiveToCosmosHubChannelId && baseDenom ===atomToken.denom,) asIbcTokenconstcanonicalDenomHash=atomDenomFromSupply.denom/* format amount for transfer */constamount= { denom: canonicalDenomHash, amount:newBigNumberInBase(0.001).toWei(atomDenomFromSupply.decimals).toString(),}constinjectiveAddress='inj...'constdestinationAddress='cosmos...'constport='transfer'consttimeoutTimestamp=makeTimeoutTimestampInNs()/* get the latestBlock from the origin chain */consttendermintRestApi=newChainRestTendermintApi(endpointsForNetwork.rest)/* Block details from the origin chain */constlatestBlock=awaittendermintRestApi.fetchLatestBlock()constlatestHeight=latestBlock.header.heightconsttimeoutHeight=newBigNumberInBase(latestHeight).plus(30,// default block timeout height)/* create message in proto format */constmsg=MsgTransfer.fromJSON({ port, memo:`IBC transfer from ${injectiveChainId} to ${destinationChainId}`, sender: injectiveAddress, receiver: destinationAddress, channelId: injectiveToCosmosHubChannelId, timeout: timeoutTimestamp, height: { revisionHeight:timeoutHeight.toNumber(), revisionNumber:parseInt(latestBlock.header.version.block,10), }, amount,})constprivateKey='0x...'/* broadcast transaction */consttxHash=awaitnewMsgBroadcasterWithPk({ privateKey, network:Network.Mainnet,}).broadcast({ msgs: msg,})console.log(txHash)