// SPDX-License-Identifier: Apache-2.0 pragma solidity >=0.8.0; import {GasRouter} from "@hyperlane-xyz/core/contracts/GasRouter.sol"; import {TypeCasts} from "@hyperlane-xyz/core/contracts/libs/TypeCasts.sol"; import {Message} from "./Message.sol"; /** * @title Hyperlane Token Router that extends Router with abstract token (ERC20/ERC721) remote transfer functionality. * @author Abacus Works */ abstract contract TokenRouter is GasRouter { using TypeCasts for bytes32; using TypeCasts for address; using Message for bytes; /** * @dev Emitted on `transferRemote` when a transfer message is dispatched. * @param destination The identifier of the destination chain. * @param recipient The address of the recipient on the destination chain. * @param amount The amount of tokens burnt on the origin chain. */ event SentTransferRemote( uint32 indexed destination, bytes32 indexed recipient, uint256 amount ); /** * @dev Emitted on `_handle` when a transfer message is processed. * @param origin The identifier of the origin chain. * @param recipient The address of the recipient on the destination chain. * @param amount The amount of tokens minted on the destination chain. */ event ReceivedTransferRemote( uint32 indexed origin, bytes32 indexed recipient, uint256 amount ); /** * @notice Transfers `_amountOrId` token to `_recipient` on `_destination` domain. * @dev Delegates transfer logic to `_transferFromSender` implementation. * @dev Emits `SentTransferRemote` event on the origin chain. * @param _destination The identifier of the destination chain. * @param _recipient The address of the recipient on the destination chain. * @param _amountOrId The amount or identifier of tokens to be sent to the remote recipient. * @return messageId The identifier of the dispatched message. */ function transferRemote( uint32 _destination, bytes32 _recipient, uint256 _amountOrId ) public payable virtual returns (bytes32 messageId) { bytes memory metadata = _transferFromSender(_amountOrId); messageId = _dispatchWithGas( _destination, Message.format(_recipient, _amountOrId, metadata), msg.value, // interchain gas payment msg.sender // refund address ); emit SentTransferRemote(_destination, _recipient, _amountOrId); } /** * @dev Should transfer `_amountOrId` of tokens from `msg.sender` to this token router. * @dev Called by `transferRemote` before message dispatch. * @dev Optionally returns `metadata` associated with the transfer to be passed in message. */ function _transferFromSender(uint256 _amountOrId) internal virtual returns (bytes memory metadata); /** * @dev Mints tokens to recipient when router receives transfer message. * @dev Emits `ReceivedTransferRemote` event on the destination chain. * @param _origin The identifier of the origin chain. * @param _message The encoded remote transfer message containing the recipient address and amount. */ function _handle( uint32 _origin, bytes32, bytes calldata _message ) internal override { bytes32 recipient = _message.recipient(); uint256 amount = _message.amount(); bytes calldata metadata = _message.metadata(); _transferTo(recipient.bytes32ToAddress(), amount, metadata); emit ReceivedTransferRemote(_origin, recipient, amount); } /** * @dev Should transfer `_amountOrId` of tokens from this token router to `_recipient`. * @dev Called by `handle` after message decoding. * @dev Optionally handles `metadata` associated with transfer passed in message. */ function _transferTo( address _recipient, uint256 _amountOrId, bytes calldata metadata ) internal virtual; }