creation_sourcecode: {{
    "language": "Solidity",
    "sources": {
      "@axelar-network/axelar-gmp-sdk-solidity/contracts/interfaces/IContractIdentifier.sol": {
        "content": "// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.0;\n\n// General interface for upgradable contracts\ninterface IContractIdentifier {\n    /**\n     * @notice Returns the contract ID. It can be used as a check during upgrades.\n     * @dev Meant to be overridden in derived contracts.\n     * @return bytes32 The contract ID\n     */\n    function contractId() external pure returns (bytes32);\n}\n"
      },
      "@axelar-network/axelar-gmp-sdk-solidity/contracts/interfaces/IERC20.sol": {
        "content": "// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n    error InvalidAccount();\n\n    /**\n     * @dev Returns the amount of tokens in existence.\n     */\n    function totalSupply() external view returns (uint256);\n\n    /**\n     * @dev Returns the amount of tokens owned by `account`.\n     */\n    function balanceOf(address account) external view returns (uint256);\n\n    /**\n     * @dev Moves `amount` tokens from the caller's account to `recipient`.\n     *\n     * Returns a boolean value indicating whether the operation succeeded.\n     *\n     * Emits a {Transfer} event.\n     */\n    function transfer(address recipient, uint256 amount) external returns (bool);\n\n    /**\n     * @dev Returns the remaining number of tokens that `spender` will be\n     * allowed to spend on behalf of `owner` through {transferFrom}. This is\n     * zero by default.\n     *\n     * This value changes when {approve} or {transferFrom} are called.\n     */\n    function allowance(address owner, address spender) external view returns (uint256);\n\n    /**\n     * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\n     *\n     * Returns a boolean value indicating whether the operation succeeded.\n     *\n     * IMPORTANT: Beware that changing an allowance with this method brings the risk\n     * that someone may use both the old and the new allowance by unfortunate\n     * transaction ordering. One possible solution to mitigate this race\n     * condition is to first reduce the spender's allowance to 0 and set the\n     * desired value afterwards:\n     * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n     *\n     * Emits an {Approval} event.\n     */\n    function approve(address spender, uint256 amount) external returns (bool);\n\n    /**\n     * @dev Moves `amount` tokens from `sender` to `recipient` using the\n     * allowance mechanism. `amount` is then deducted from the caller's\n     * allowance.\n     *\n     * Returns a boolean value indicating whether the operation succeeded.\n     *\n     * Emits a {Transfer} event.\n     */\n    function transferFrom(\n        address sender,\n        address recipient,\n        uint256 amount\n    ) external returns (bool);\n\n    /**\n     * @dev Emitted when `value` tokens are moved from one account (`from`) to\n     * another (`to`).\n     *\n     * Note that `value` may be zero.\n     */\n    event Transfer(address indexed from, address indexed to, uint256 value);\n\n    /**\n     * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n     * a call to {approve}. `value` is the new allowance.\n     */\n    event Approval(address indexed owner, address indexed spender, uint256 value);\n}\n"
      },
      "@axelar-network/axelar-gmp-sdk-solidity/contracts/interfaces/IImplementation.sol": {
        "content": "// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.0;\n\nimport { IContractIdentifier } from './IContractIdentifier.sol';\n\ninterface IImplementation is IContractIdentifier {\n    error NotProxy();\n\n    function setup(bytes calldata data) external;\n}\n"
      },
      "@axelar-network/axelar-gmp-sdk-solidity/contracts/interfaces/IReentrancyGuard.sol": {
        "content": "// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.0;\n\n/**\n * @title ReentrancyGuard\n * @notice This contract provides a mechanism to halt the execution of specific functions\n * if a pause condition is activated.\n */\ninterface IReentrancyGuard {\n    error ReentrantCall();\n}\n"
      },
      "@axelar-network/axelar-gmp-sdk-solidity/contracts/interfaces/IRolesBase.sol": {
        "content": "// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.0;\n\n/**\n * @title IRolesBase Interface\n * @notice IRolesBase is an interface that abstracts the implementation of a\n * contract with role control internal functions.\n */\ninterface IRolesBase {\n    error MissingRole(address account, uint8 role);\n    error MissingAllRoles(address account, uint256 accountRoles);\n    error MissingAnyOfRoles(address account, uint256 accountRoles);\n\n    error InvalidProposedRoles(address fromAccount, address toAccount, uint256 accountRoles);\n\n    event RolesProposed(address indexed fromAccount, address indexed toAccount, uint256 accountRoles);\n    event RolesAdded(address indexed account, uint256 accountRoles);\n    event RolesRemoved(address indexed account, uint256 accountRoles);\n\n    /**\n     * @notice Checks if an account has a role.\n     * @param account The address to check\n     * @param role The role to check\n     * @return True if the account has the role, false otherwise\n     */\n    function hasRole(address account, uint8 role) external view returns (bool);\n}\n"
      },
      "@axelar-network/axelar-gmp-sdk-solidity/contracts/libs/SafeTransfer.sol": {
        "content": "// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.0;\n\nimport { IERC20 } from '../interfaces/IERC20.sol';\n\nerror TokenTransferFailed();\n\n/*\n * @title SafeTokenCall\n * @dev This library is used for performing safe token transfers.\n */\nlibrary SafeTokenCall {\n    /*\n     * @notice Make a safe call to a token contract.\n     * @param token The token contract to interact with.\n     * @param callData The function call data.\n     * @throws TokenTransferFailed error if transfer of token is not successful.\n     */\n    function safeCall(IERC20 token, bytes memory callData) internal {\n        (bool success, bytes memory returnData) = address(token).call(callData);\n        bool transferred = success && (returnData.length == uint256(0) || abi.decode(returnData, (bool)));\n\n        if (!transferred || address(token).code.length == 0) revert TokenTransferFailed();\n    }\n}\n\n/*\n * @title SafeTokenTransfer\n * @dev This library safely transfers tokens from the contract to a recipient.\n */\nlibrary SafeTokenTransfer {\n    /*\n     * @notice Transfer tokens to a recipient.\n     * @param token The token contract.\n     * @param receiver The recipient of the tokens.\n     * @param amount The amount of tokens to transfer.\n     */\n    function safeTransfer(\n        IERC20 token,\n        address receiver,\n        uint256 amount\n    ) internal {\n        SafeTokenCall.safeCall(token, abi.encodeWithSelector(IERC20.transfer.selector, receiver, amount));\n    }\n}\n\n/*\n * @title SafeTokenTransferFrom\n * @dev This library helps to safely transfer tokens on behalf of a token holder.\n */\nlibrary SafeTokenTransferFrom {\n    /*\n     * @notice Transfer tokens on behalf of a token holder.\n     * @param token The token contract.\n     * @param from The address of the token holder.\n     * @param to The address the tokens are to be sent to.\n     * @param amount The amount of tokens to be transferred.\n     */\n    function safeTransferFrom(\n        IERC20 token,\n        address from,\n        address to,\n        uint256 amount\n    ) internal {\n        SafeTokenCall.safeCall(token, abi.encodeWithSelector(IERC20.transferFrom.selector, from, to, amount));\n    }\n}\n"
      },
      "@axelar-network/axelar-gmp-sdk-solidity/contracts/utils/ReentrancyGuard.sol": {
        "content": "// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.0;\n\nimport { IReentrancyGuard } from '../interfaces/IReentrancyGuard.sol';\n\n/**\n * @title ReentrancyGuard\n * @notice This contract provides a mechanism to halt the execution of specific functions\n * if a pause condition is activated.\n */\ncontract ReentrancyGuard is IReentrancyGuard {\n    // uint256(keccak256('ReentrancyGuard:entered')) - 1\n    uint256 internal constant ENTERED_SLOT = 0x1a771c70cada93a906f955a7dec24a83d7954ba2f75256be4febcf62b395d532;\n    uint256 internal constant NOT_ENTERED = 1;\n    uint256 internal constant ENTERED = 2;\n\n    /**\n     * @notice A modifier that throws a ReEntrancy custom error if the contract is entered\n     * @dev This modifier should be used with functions that can be entered twice\n     */\n    modifier noReEntrancy() {\n        if (_hasEntered()) revert ReentrantCall();\n        _setEntered(ENTERED);\n        _;\n        _setEntered(NOT_ENTERED);\n    }\n\n    /**\n     * @notice Check if the contract is already executing.\n     * @return entered A boolean representing the entered status. True if already executing, false otherwise.\n     */\n    function _hasEntered() internal view returns (bool entered) {\n        assembly {\n            entered := eq(sload(ENTERED_SLOT), ENTERED)\n        }\n    }\n\n    /**\n     * @notice Sets the entered status of the contract\n     * @param entered A boolean representing the entered status. True if already executing, false otherwise.\n     */\n    function _setEntered(uint256 entered) internal {\n        assembly {\n            sstore(ENTERED_SLOT, entered)\n        }\n    }\n}\n"
      },
      "contracts/interfaces/IBaseTokenManager.sol": {
        "content": "// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.0;\n\n/**\n * @title IBaseTokenManager\n * @notice This contract is defines the base token manager interface implemented by all token managers.\n */\ninterface IBaseTokenManager {\n    /**\n     * @notice A function that returns the token id.\n     */\n    function interchainTokenId() external view returns (bytes32);\n\n    /**\n     * @notice A function that should return the address of the token.\n     * Must be overridden in the inheriting contract.\n     * @return address address of the token.\n     */\n    function tokenAddress() external view returns (address);\n\n    /**\n     * @notice A function that should return the token address from the init params.\n     */\n    function getTokenAddressFromParams(bytes calldata params) external pure returns (address);\n}\n"
      },
      "contracts/interfaces/IERC20BurnableFrom.sol": {
        "content": "// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.0;\n\n/**\n * @title IERC20BurnableFrom Interface\n * @notice Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20BurnableFrom {\n    /**\n     * @notice Function to burn tokens.\n     * @dev Requires the caller to have allowance for `amount` on `from`.\n     * Can only be called by the minter address.\n     * @param from The address that will have its tokens burnt.\n     * @param amount The amount of tokens to burn.\n     */\n    function burnFrom(address from, uint256 amount) external;\n}\n"
      },
      "contracts/interfaces/IERC20MintableBurnable.sol": {
        "content": "// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.0;\n\n/**\n * @title IERC20MintableBurnable Interface\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20MintableBurnable {\n    /**\n     * @notice Function to mint new tokens.\n     * @dev Can only be called by the minter address.\n     * @param to The address that will receive the minted tokens.\n     * @param amount The amount of tokens to mint.\n     */\n    function mint(address to, uint256 amount) external;\n\n    /**\n     * @notice Function to burn tokens.\n     * @dev Can only be called by the minter address.\n     * @param from The address that will have its tokens burnt.\n     * @param amount The amount of tokens to burn.\n     */\n    function burn(address from, uint256 amount) external;\n}\n"
      },
      "contracts/interfaces/IFlowLimit.sol": {
        "content": "// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.0;\n\n/**\n * @title FlowLimit Interface\n * @notice Interface for flow limit logic for interchain token transfers.\n */\ninterface IFlowLimit {\n    error FlowLimitExceeded(uint256 limit, uint256 flowAmount, address tokenManager);\n\n    event FlowLimitSet(bytes32 indexed tokenId, address operator, uint256 flowLimit_);\n\n    /**\n     * @notice Returns the current flow limit.\n     * @return flowLimit_ The current flow limit value.\n     */\n    function flowLimit() external view returns (uint256 flowLimit_);\n\n    /**\n     * @notice Returns the current flow out amount.\n     * @return flowOutAmount_ The current flow out amount.\n     */\n    function flowOutAmount() external view returns (uint256 flowOutAmount_);\n\n    /**\n     * @notice Returns the current flow in amount.\n     * @return flowInAmount_ The current flow in amount.\n     */\n    function flowInAmount() external view returns (uint256 flowInAmount_);\n}\n"
      },
      "contracts/interfaces/IOperator.sol": {
        "content": "// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.0;\n\nimport { IRolesBase } from '@axelar-network/axelar-gmp-sdk-solidity/contracts/interfaces/IRolesBase.sol';\n\n/**\n * @title IOperator Interface\n * @notice An interface for a contract module which provides a basic access control mechanism, where\n * there is an account (a operator) that can be granted exclusive access to specific functions.\n */\ninterface IOperator is IRolesBase {\n    /**\n     * @notice Change the operator of the contract.\n     * @dev Can only be called by the current operator.\n     * @param operator_ The address of the new operator.\n     */\n    function transferOperatorship(address operator_) external;\n\n    /**\n     * @notice Proposed a change of the operator of the contract.\n     * @dev Can only be called by the current operator.\n     * @param operator_ The address of the new operator.\n     */\n    function proposeOperatorship(address operator_) external;\n\n    /**\n     * @notice Accept a proposed change of operatorship.\n     * @dev Can only be called by the proposed operator.\n     * @param fromOperator The previous operator of the contract.\n     */\n    function acceptOperatorship(address fromOperator) external;\n\n    /**\n     * @notice Query if an address is a operator.\n     * @param addr The address to query for.\n     * @return bool Boolean value representing whether or not the address is an operator.\n     */\n    function isOperator(address addr) external view returns (bool);\n}\n"
      },
      "contracts/interfaces/ITokenHandler.sol": {
        "content": "// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.0;\n\n/**\n * @title ITokenHandler Interface\n * @notice This interface is responsible for handling tokens before initiating an interchain token transfer, or after receiving one.\n */\ninterface ITokenHandler {\n    error UnsupportedTokenManagerType(uint256 tokenManagerType);\n\n    /**\n     * @notice This function gives token to a specified address from the token manager.\n     * @param tokenManagerType The token manager type.\n     * @param tokenAddress The address of the token to give.\n     * @param tokenManager The address of the token manager.\n     * @param to The address to give tokens to.\n     * @param amount The amount of tokens to give.\n     * @return uint256 The amount of token actually given, which could be different for certain token type.\n     */\n    function giveToken(\n        uint256 tokenManagerType,\n        address tokenAddress,\n        address tokenManager,\n        address to,\n        uint256 amount\n    ) external payable returns (uint256);\n\n    /**\n     * @notice This function takes token from a specified address to the token manager.\n     * @param tokenManagerType The token manager type.\n     * @param tokenAddress The address of the token to give.\n     * @param tokenManager The address of the token manager.\n     * @param from The address to take tokens from.\n     * @param amount The amount of token to take.\n     * @return uint256 The amount of token actually taken, which could be different for certain token type.\n     */\n    function takeToken(\n        uint256 tokenManagerType,\n        address tokenAddress,\n        address tokenManager,\n        address from,\n        uint256 amount\n    ) external payable returns (uint256);\n\n    /**\n     * @notice This function transfers token from and to a specified address.\n     * @param tokenManagerType The token manager type.\n     * @param tokenAddress the address of the token to give.\n     * @param from The address to transfer tokens from.\n     * @param to The address to transfer tokens to.\n     * @param amount The amount of token to transfer.\n     * @return uint256 The amount of token actually transferred, which could be different for certain token type.\n     */\n    function transferTokenFrom(\n        uint256 tokenManagerType,\n        address tokenAddress,\n        address from,\n        address to,\n        uint256 amount\n    ) external payable returns (uint256);\n}\n"
      },
      "contracts/interfaces/ITokenManager.sol": {
        "content": "// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.0;\n\nimport { IImplementation } from '@axelar-network/axelar-gmp-sdk-solidity/contracts/interfaces/IImplementation.sol';\n\nimport { IBaseTokenManager } from './IBaseTokenManager.sol';\nimport { IOperator } from './IOperator.sol';\nimport { IFlowLimit } from './IFlowLimit.sol';\n\n/**\n * @title ITokenManager Interface\n * @notice This contract is responsible for managing tokens, such as setting locking token balances, or setting flow limits, for interchain transfers.\n */\ninterface ITokenManager is IBaseTokenManager, IOperator, IFlowLimit, IImplementation {\n    error TokenLinkerZeroAddress();\n    error NotService(address caller);\n    error TakeTokenFailed();\n    error GiveTokenFailed();\n    error NotToken(address caller);\n    error ZeroAddress();\n    error AlreadyFlowLimiter(address flowLimiter);\n    error NotFlowLimiter(address flowLimiter);\n    error NotSupported();\n\n    /**\n     * @notice Returns implementation type of this token manager.\n     * @return uint256 The implementation type of this token manager.\n     */\n    function implementationType() external view returns (uint256);\n\n    function addFlowIn(uint256 amount) external;\n\n    function addFlowOut(uint256 amount) external;\n\n    /**\n     * @notice This function adds a flow limiter for this TokenManager.\n     * @dev Can only be called by the operator.\n     * @param flowLimiter the address of the new flow limiter.\n     */\n    function addFlowLimiter(address flowLimiter) external;\n\n    /**\n     * @notice This function removes a flow limiter for this TokenManager.\n     * @dev Can only be called by the operator.\n     * @param flowLimiter the address of an existing flow limiter.\n     */\n    function removeFlowLimiter(address flowLimiter) external;\n\n    /**\n     * @notice Query if an address is a flow limiter.\n     * @param addr The address to query for.\n     * @return bool Boolean value representing whether or not the address is a flow limiter.\n     */\n    function isFlowLimiter(address addr) external view returns (bool);\n\n    /**\n     * @notice This function sets the flow limit for this TokenManager.\n     * @dev Can only be called by the flow limiters.\n     * @param flowLimit_ The maximum difference between the tokens flowing in and/or out at any given interval of time (6h).\n     */\n    function setFlowLimit(uint256 flowLimit_) external;\n\n    /**\n     * @notice A function to renew approval to the service if we need to.\n     */\n    function approveService() external;\n\n    /**\n     * @notice Getter function for the parameters of a lock/unlock TokenManager.\n     * @dev This function will be mainly used by frontends.\n     * @param operator_ The operator of the TokenManager.\n     * @param tokenAddress_ The token to be managed.\n     * @return params_ The resulting params to be passed to custom TokenManager deployments.\n     */\n    function params(bytes calldata operator_, address tokenAddress_) external pure returns (bytes memory params_);\n\n    /**\n     * @notice External function to allow the service to mint tokens through the tokenManager\n     * @dev This function should revert if called by anyone but the service.\n     * @param tokenAddress_ The address of the token, since its cheaper to pass it in instead of reading it as the token manager.\n     * @param to The recipient.\n     * @param amount The amount to mint.\n     */\n    function mintToken(address tokenAddress_, address to, uint256 amount) external;\n\n    /**\n     * @notice External function to allow the service to burn tokens through the tokenManager\n     * @dev This function should revert if called by anyone but the service.\n     * @param tokenAddress_ The address of the token, since its cheaper to pass it in instead of reading it as the token manager.\n     * @param from The address to burn the token from.\n     * @param amount The amount to burn.\n     */\n    function burnToken(address tokenAddress_, address from, uint256 amount) external;\n}\n"
      },
      "contracts/interfaces/ITokenManagerType.sol": {
        "content": "// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.0;\n\n/**\n * @title ITokenManagerType Interface\n * @notice A simple interface that defines all the token manager types.\n */\ninterface ITokenManagerType {\n    enum TokenManagerType {\n        NATIVE_INTERCHAIN_TOKEN, // This type is reserved for interchain tokens deployed by ITS, and can't be used by custom token managers.\n        MINT_BURN_FROM, // The token will be minted/burned on transfers. The token needs to give mint permission to the token manager, but burning happens via an approval.\n        LOCK_UNLOCK, // The token will be locked/unlocked at the token manager.\n        LOCK_UNLOCK_FEE, // The token will be locked/unlocked at the token manager, which will account for any fee-on-transfer behaviour.\n        MINT_BURN // The token will be minted/burned on transfers. The token needs to give mint and burn permission to the token manager.\n    }\n}\n"
      },
      "contracts/TokenHandler.sol": {
        "content": "// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.0;\n\nimport { ITokenHandler } from './interfaces/ITokenHandler.sol';\nimport { IERC20 } from '@axelar-network/axelar-gmp-sdk-solidity/contracts/interfaces/IERC20.sol';\nimport { SafeTokenTransferFrom, SafeTokenCall } from '@axelar-network/axelar-gmp-sdk-solidity/contracts/libs/SafeTransfer.sol';\nimport { ReentrancyGuard } from '@axelar-network/axelar-gmp-sdk-solidity/contracts/utils/ReentrancyGuard.sol';\n\nimport { ITokenManagerType } from './interfaces/ITokenManagerType.sol';\nimport { ITokenManager } from './interfaces/ITokenManager.sol';\nimport { IERC20MintableBurnable } from './interfaces/IERC20MintableBurnable.sol';\nimport { IERC20BurnableFrom } from './interfaces/IERC20BurnableFrom.sol';\n\n/**\n * @title TokenHandler\n * @notice This interface is responsible for handling tokens before initiating an interchain token transfer, or after receiving one.\n */\ncontract TokenHandler is ITokenHandler, ITokenManagerType, ReentrancyGuard {\n    using SafeTokenTransferFrom for IERC20;\n    using SafeTokenCall for IERC20;\n\n    /**\n     * @notice This function gives token to a specified address from the token manager.\n     * @param tokenManagerType The token manager type.\n     * @param tokenAddress The address of the token to give.\n     * @param tokenManager The address of the token manager.\n     * @param to The address to give tokens to.\n     * @param amount The amount of tokens to give.\n     * @return uint256 The amount of token actually given, which could be different for certain token type.\n     */\n    // slither-disable-next-line locked-ether\n    function giveToken(\n        uint256 tokenManagerType,\n        address tokenAddress,\n        address tokenManager,\n        address to,\n        uint256 amount\n    ) external payable returns (uint256) {\n        if (tokenManagerType == uint256(TokenManagerType.NATIVE_INTERCHAIN_TOKEN)) {\n            _giveInterchainToken(tokenAddress, to, amount);\n            return amount;\n        }\n\n        if (tokenManagerType == uint256(TokenManagerType.MINT_BURN) || tokenManagerType == uint256(TokenManagerType.MINT_BURN_FROM)) {\n            _mintToken(tokenManager, tokenAddress, to, amount);\n            return amount;\n        }\n\n        if (tokenManagerType == uint256(TokenManagerType.LOCK_UNLOCK)) {\n            _transferTokenFrom(tokenAddress, tokenManager, to, amount);\n            return amount;\n        }\n\n        if (tokenManagerType == uint256(TokenManagerType.LOCK_UNLOCK_FEE)) {\n            amount = _transferTokenFromWithFee(tokenAddress, tokenManager, to, amount);\n            return amount;\n        }\n\n        revert UnsupportedTokenManagerType(tokenManagerType);\n    }\n\n    /**\n     * @notice This function takes token from a specified address to the token manager.\n     * @param tokenManagerType The token manager type.\n     * @param tokenAddress The address of the token to give.\n     * @param tokenManager The address of the token manager.\n     * @param from The address to take tokens from.\n     * @param amount The amount of token to take.\n     * @return uint256 The amount of token actually taken, which could be different for certain token type.\n     */\n    // slither-disable-next-line locked-ether\n    function takeToken(\n        uint256 tokenManagerType,\n        address tokenAddress,\n        address tokenManager,\n        address from,\n        uint256 amount\n    ) external payable returns (uint256) {\n        if (tokenManagerType == uint256(TokenManagerType.NATIVE_INTERCHAIN_TOKEN)) {\n            _takeInterchainToken(tokenAddress, from, amount);\n            return amount;\n        }\n\n        if (tokenManagerType == uint256(TokenManagerType.MINT_BURN)) {\n            _burnToken(tokenManager, tokenAddress, from, amount);\n            return amount;\n        }\n\n        if (tokenManagerType == uint256(TokenManagerType.MINT_BURN_FROM)) {\n            _burnTokenFrom(tokenAddress, from, amount);\n            return amount;\n        }\n\n        if (tokenManagerType == uint256(TokenManagerType.LOCK_UNLOCK)) {\n            _transferTokenFrom(tokenAddress, from, tokenManager, amount);\n            return amount;\n        }\n\n        if (tokenManagerType == uint256(TokenManagerType.LOCK_UNLOCK_FEE)) {\n            amount = _transferTokenFromWithFee(tokenAddress, from, tokenManager, amount);\n            return amount;\n        }\n\n        revert UnsupportedTokenManagerType(tokenManagerType);\n    }\n\n    /**\n     * @notice This function transfers token from and to a specified address.\n     * @param tokenManagerType The token manager type.\n     * @param tokenAddress the address of the token to give.\n     * @param from The address to transfer tokens from.\n     * @param to The address to transfer tokens to.\n     * @param amount The amount of token to transfer.\n     * @return uint256 The amount of token actually transferred, which could be different for certain token type.\n     */\n    // slither-disable-next-line locked-ether\n    function transferTokenFrom(\n        uint256 tokenManagerType,\n        address tokenAddress,\n        address from,\n        address to,\n        uint256 amount\n    ) external payable returns (uint256) {\n        if (\n            tokenManagerType == uint256(TokenManagerType.NATIVE_INTERCHAIN_TOKEN) ||\n            tokenManagerType == uint256(TokenManagerType.LOCK_UNLOCK) ||\n            tokenManagerType == uint256(TokenManagerType.MINT_BURN) ||\n            tokenManagerType == uint256(TokenManagerType.MINT_BURN_FROM)\n        ) {\n            _transferTokenFrom(tokenAddress, from, to, amount);\n            return amount;\n        }\n\n        if (tokenManagerType == uint256(TokenManagerType.LOCK_UNLOCK_FEE)) {\n            amount = _transferTokenFromWithFee(tokenAddress, from, to, amount);\n            return amount;\n        }\n\n        revert UnsupportedTokenManagerType(tokenManagerType);\n    }\n\n    function _transferTokenFrom(address tokenAddress, address from, address to, uint256 amount) internal {\n        // slither-disable-next-line arbitrary-send-erc20\n        IERC20(tokenAddress).safeTransferFrom(from, to, amount);\n    }\n\n    function _transferTokenFromWithFee(\n        address tokenAddress,\n        address from,\n        address to,\n        uint256 amount\n    ) internal noReEntrancy returns (uint256) {\n        uint256 balanceBefore = IERC20(tokenAddress).balanceOf(to);\n\n        _transferTokenFrom(tokenAddress, from, to, amount);\n\n        uint256 diff = IERC20(tokenAddress).balanceOf(to) - balanceBefore;\n        if (diff < amount) {\n            amount = diff;\n        }\n\n        return amount;\n    }\n\n    function _giveInterchainToken(address tokenAddress, address to, uint256 amount) internal {\n        IERC20(tokenAddress).safeCall(abi.encodeWithSelector(IERC20MintableBurnable.mint.selector, to, amount));\n    }\n\n    function _takeInterchainToken(address tokenAddress, address from, uint256 amount) internal {\n        IERC20(tokenAddress).safeCall(abi.encodeWithSelector(IERC20MintableBurnable.burn.selector, from, amount));\n    }\n\n    function _mintToken(address tokenManager, address tokenAddress, address to, uint256 amount) internal {\n        ITokenManager(tokenManager).mintToken(tokenAddress, to, amount);\n    }\n\n    function _burnToken(address tokenManager, address tokenAddress, address from, uint256 amount) internal {\n        ITokenManager(tokenManager).burnToken(tokenAddress, from, amount);\n    }\n\n    function _burnTokenFrom(address tokenAddress, address from, uint256 amount) internal {\n        IERC20(tokenAddress).safeCall(abi.encodeWithSelector(IERC20BurnableFrom.burnFrom.selector, from, amount));\n    }\n}\n"
      }
    },
    "settings": {
      "evmVersion": "london",
      "optimizer": {
        "enabled": true,
        "runs": 1000,
        "details": {
          "peephole": true,
          "inliner": true,
          "jumpdestRemover": true,
          "orderLiterals": true,
          "deduplicate": true,
          "cse": true,
          "constantOptimizer": true,
          "yul": true,
          "yulDetails": {
            "stackAllocation": true
          }
        }
      },
      "outputSelection": {
        "*": {
          "*": [
            "evm.bytecode",
            "evm.deployedBytecode",
            "devdoc",
            "userdoc",
            "metadata",
            "abi"
          ]
        }
      },
      "libraries": {}
    }
  }}