creation_sourcecode: {{
    "language": "Solidity",
    "sources": {
      "@openzeppelin/contracts-upgradeable/proxy/Initializable.sol": {
        "content": "// SPDX-License-Identifier: MIT\n\n// solhint-disable-next-line compiler-version\npragma solidity >=0.4.24 <0.8.0;\n\nimport \"../utils/AddressUpgradeable.sol\";\n\n/**\n * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed\n * behind a proxy. Since a proxied contract can't have a constructor, it's common to move constructor logic to an\n * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer\n * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.\n *\n * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as\n * possible by providing the encoded function call as the `_data` argument to {UpgradeableProxy-constructor}.\n *\n * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure\n * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.\n */\nabstract contract Initializable {\n\n    /**\n     * @dev Indicates that the contract has been initialized.\n     */\n    bool private _initialized;\n\n    /**\n     * @dev Indicates that the contract is in the process of being initialized.\n     */\n    bool private _initializing;\n\n    /**\n     * @dev Modifier to protect an initializer function from being invoked twice.\n     */\n    modifier initializer() {\n        require(_initializing || _isConstructor() || !_initialized, \"Initializable: contract is already initialized\");\n\n        bool isTopLevelCall = !_initializing;\n        if (isTopLevelCall) {\n            _initializing = true;\n            _initialized = true;\n        }\n\n        _;\n\n        if (isTopLevelCall) {\n            _initializing = false;\n        }\n    }\n\n    /// @dev Returns true if and only if the function is running in the constructor\n    function _isConstructor() private view returns (bool) {\n        return !AddressUpgradeable.isContract(address(this));\n    }\n}\n"
      },
      "@openzeppelin/contracts-upgradeable/utils/AddressUpgradeable.sol": {
        "content": "// SPDX-License-Identifier: MIT\n\npragma solidity >=0.6.2 <0.8.0;\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary AddressUpgradeable {\n    /**\n     * @dev Returns true if `account` is a contract.\n     *\n     * [IMPORTANT]\n     * ====\n     * It is unsafe to assume that an address for which this function returns\n     * false is an externally-owned account (EOA) and not a contract.\n     *\n     * Among others, `isContract` will return false for the following\n     * types of addresses:\n     *\n     *  - an externally-owned account\n     *  - a contract in construction\n     *  - an address where a contract will be created\n     *  - an address where a contract lived, but was destroyed\n     * ====\n     */\n    function isContract(address account) internal view returns (bool) {\n        // This method relies on extcodesize, which returns 0 for contracts in\n        // construction, since the code is only stored at the end of the\n        // constructor execution.\n\n        uint256 size;\n        // solhint-disable-next-line no-inline-assembly\n        assembly { size := extcodesize(account) }\n        return size > 0;\n    }\n\n    /**\n     * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\n     * `recipient`, forwarding all available gas and reverting on errors.\n     *\n     * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\n     * of certain opcodes, possibly making contracts go over the 2300 gas limit\n     * imposed by `transfer`, making them unable to receive funds via\n     * `transfer`. {sendValue} removes this limitation.\n     *\n     * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\n     *\n     * IMPORTANT: because control is transferred to `recipient`, care must be\n     * taken to not create reentrancy vulnerabilities. Consider using\n     * {ReentrancyGuard} or the\n     * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n     */\n    function sendValue(address payable recipient, uint256 amount) internal {\n        require(address(this).balance >= amount, \"Address: insufficient balance\");\n\n        // solhint-disable-next-line avoid-low-level-calls, avoid-call-value\n        (bool success, ) = recipient.call{ value: amount }(\"\");\n        require(success, \"Address: unable to send value, recipient may have reverted\");\n    }\n\n    /**\n     * @dev Performs a Solidity function call using a low level `call`. A\n     * plain`call` is an unsafe replacement for a function call: use this\n     * function instead.\n     *\n     * If `target` reverts with a revert reason, it is bubbled up by this\n     * function (like regular Solidity function calls).\n     *\n     * Returns the raw returned data. To convert to the expected return value,\n     * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\n     *\n     * Requirements:\n     *\n     * - `target` must be a contract.\n     * - calling `target` with `data` must not revert.\n     *\n     * _Available since v3.1._\n     */\n    function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n      return functionCall(target, data, \"Address: low-level call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\n     * `errorMessage` as a fallback revert reason when `target` reverts.\n     *\n     * _Available since v3.1._\n     */\n    function functionCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, 0, errorMessage);\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n     * but also transferring `value` wei to `target`.\n     *\n     * Requirements:\n     *\n     * - the calling contract must have an ETH balance of at least `value`.\n     * - the called Solidity function must be `payable`.\n     *\n     * _Available since v3.1._\n     */\n    function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, value, \"Address: low-level call with value failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\n     * with `errorMessage` as a fallback revert reason when `target` reverts.\n     *\n     * _Available since v3.1._\n     */\n    function functionCallWithValue(address target, bytes memory data, uint256 value, string memory errorMessage) internal returns (bytes memory) {\n        require(address(this).balance >= value, \"Address: insufficient balance for call\");\n        require(isContract(target), \"Address: call to non-contract\");\n\n        // solhint-disable-next-line avoid-low-level-calls\n        (bool success, bytes memory returndata) = target.call{ value: value }(data);\n        return _verifyCallResult(success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n     * but performing a static call.\n     *\n     * _Available since v3.3._\n     */\n    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n        return functionStaticCall(target, data, \"Address: low-level static call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n     * but performing a static call.\n     *\n     * _Available since v3.3._\n     */\n    function functionStaticCall(address target, bytes memory data, string memory errorMessage) internal view returns (bytes memory) {\n        require(isContract(target), \"Address: static call to non-contract\");\n\n        // solhint-disable-next-line avoid-low-level-calls\n        (bool success, bytes memory returndata) = target.staticcall(data);\n        return _verifyCallResult(success, returndata, errorMessage);\n    }\n\n    function _verifyCallResult(bool success, bytes memory returndata, string memory errorMessage) private pure returns(bytes memory) {\n        if (success) {\n            return returndata;\n        } else {\n            // Look for revert reason and bubble it up if present\n            if (returndata.length > 0) {\n                // The easiest way to bubble the revert reason is using memory via assembly\n\n                // solhint-disable-next-line no-inline-assembly\n                assembly {\n                    let returndata_size := mload(returndata)\n                    revert(add(32, returndata), returndata_size)\n                }\n            } else {\n                revert(errorMessage);\n            }\n        }\n    }\n}\n"
      },
      "contracts/interfaces/IErc20MessageBroker.sol": {
        "content": "// SPDX-License-Identifier: MIT\r\npragma solidity >=0.6.12 <0.8.20;\r\npragma abicoder v2;\r\n\r\nstruct CCIPBroker {\r\n    uint64 sourceChainSelector;\r\n    address receiverContract;\r\n    bool allowMessagesTo;\r\n    bool allowMessagesFrom;\r\n}\r\n\r\ninterface IErc20MessageBroker  {\r\n    function sendMessage( \r\n        bytes32 token,\r\n        uint256 amount,\r\n        uint64 destChainId,\r\n        address depositor,\r\n        address recipient) external payable returns (bytes32);\r\n    function getFee(bytes32 token,\r\n        uint256 amount,\r\n        uint64 destChainId,\r\n        address recipient) external returns (uint256); \r\n}\r\n"
      },
      "contracts/interfaces/IMintBurnToken.sol": {
        "content": "// SPDX-License-Identifier: MIT\r\npragma solidity ^0.7.6;\r\n\r\ninterface IMintBurnToken {\r\n    function mint(address account, uint256 amount) external;\r\n\r\n    function burn(address account, uint256 amount) external;\r\n}\r\n"
      },
      "contracts/interfaces/IWormhole.sol": {
        "content": "// SPDX-License-Identifier: MIT\r\npragma solidity >=0.6.12 <0.8.0;\r\npragma abicoder v2;\r\n\r\ninterface IWormhole {\r\n    struct VM {\r\n        uint8 version;\r\n        uint32 timestamp;\r\n        uint32 nonce;\r\n        uint16 emitterChainId;\r\n        bytes32 emitterAddress;\r\n        uint64 sequence;\r\n        uint8 consistencyLevel;\r\n        bytes payload;\r\n        uint32 guardianSetIndex;\r\n        Signature[] signatures;\r\n        bytes32 hash;\r\n    }\r\n\r\n    struct Signature {\r\n        bytes32 r;\r\n        bytes32 s;\r\n        uint8 v;\r\n        uint8 guardianIndex;\r\n    }\r\n\r\n    function parseAndVerifyVM(bytes calldata encodedVM)\r\n        external\r\n        view\r\n        returns (\r\n            VM memory vm,\r\n            bool valid,\r\n            string memory reason\r\n        );\r\n\r\n    function publishMessage(\r\n        uint32 nonce,\r\n        bytes memory payload,\r\n        uint8 consistencyLevel\r\n    ) external payable returns (uint64 sequence);\r\n}\r\n"
      },
      "contracts/LnAdminableContract.sol": {
        "content": "// SPDX-License-Identifier: MIT\r\npragma solidity >=0.6.12 <= 0.8.19;\r\n\r\ncontract LnAdminableContract \r\n{    \r\n    event CandidateChanged(address oldCandidate, address newCandidate);\r\n    event AdminChanged(address oldAdmin, address newAdmin);\r\n\r\n    address public admin;\r\n    address public candidate;\r\n\r\n    function setCandidate(address _candidate) external onlyAdmin {\r\n        address old = candidate;\r\n        candidate = _candidate;\r\n        emit CandidateChanged(old, candidate);\r\n    }\r\n\r\n    function becomeAdmin() external {\r\n        require(msg.sender == candidate, \"LnAdminUpgradeable: only candidate can become admin\");\r\n        address old = admin;\r\n        admin = candidate;\r\n        emit AdminChanged(old, admin);\r\n    }\r\n\r\n    modifier onlyAdmin {\r\n        require((msg.sender == admin), \"LnAdminUpgradeable: only the contract admin can perform this action\");\r\n        _;\r\n    }\r\n}"
      },
      "contracts/LnErc20Bridge.sol": {
        "content": "// SPDX-License-Identifier: MIT\r\npragma solidity ^0.7.6;\r\npragma abicoder v2;\r\n\r\nimport \"./interfaces/IMintBurnToken.sol\";\r\nimport \"./interfaces/IWormhole.sol\";\r\nimport \"./upgradeable/LnAdminUpgradeable.sol\";\r\nimport \"./interfaces/IErc20MessageBroker.sol\";\r\n\r\n/**\r\n * @title LnErc20Bridge\r\n *\r\n * @dev An upgradeable contract for moving ERC20 tokens across blockchains. It makes use of the\r\n * Wormhole messaging functionality for verifying deposit proofs. Before Wormhole was integrated,\r\n * the contract uses a centralized relayer for deposit verification.\r\n *\r\n * @dev The bridge can operate in two different modes for each token: transfer mode and mint/burn\r\n * mode, depending on the nature of the token.\r\n *\r\n * @dev Note that transaction hashes shall NOT be used for re-entrance prevention as doing\r\n * so will result in false negatives when multiple transfers are made in a single\r\n * transaction (with the use of contracts).\r\n *\r\n * @dev Chain IDs in this contract currently refer to the ones introduced in EIP-155. However,\r\n * a list of custom IDs might be used instead when non-EVM compatible chains are added.\r\n */\r\ncontract LnErc20Bridge is LnAdminUpgradeable {\r\n    // using SafeERC20 for IERC20;\r\n    /**\r\n     * These events are no longer used. Archiving them here for reference but they won't show up in\r\n     * ABI. You need to manually edit the ABI if you want to index old events in subgraphs, for\r\n     * example.\r\n\r\n    event TokenDeposited(\r\n        uint256 srcChainId,\r\n        uint256 destChainId,\r\n        uint256 depositId,\r\n        bytes32 depositor,\r\n        bytes32 recipient,\r\n        bytes32 currency,\r\n        uint256 amount\r\n     );\r\n\r\n    event TokenDeposited(\r\n        uint256 srcChainId,\r\n        uint256 destChainId,\r\n        uint256 depositId,\r\n        bytes32 depositor,\r\n        bytes32 recipient,\r\n        bytes32 currency,\r\n        uint256 amount,\r\n        uint64 wormholeSequence\r\n     );\r\n\r\n    event TokenWithdrawn(\r\n        uint256 srcChainId,\r\n        uint256 destChainId,\r\n        uint256 depositId,\r\n        address depositor,\r\n        address recipient,\r\n        bytes32 currency,\r\n        uint256 amount\r\n    );\r\n     * event ForcedWithdrawal(uint256 srcChainId, uint256 depositId, address actualRecipient);\r\n     * event RelayerChanged(address oldRelayer, address newRelayer);\r\n     */\r\n\r\n    event TokenDeposited(\r\n        uint256 srcChainId,\r\n        uint256 destChainId,\r\n        uint256 depositId,\r\n        bytes32 depositor,\r\n        bytes32 recipient,\r\n        bytes32 currency,\r\n        uint256 amount\r\n     );\r\n\r\n    event TokenDeposited(\r\n        uint256 srcChainId,\r\n        uint256 destChainId,\r\n        uint256 depositId,\r\n        bytes32 depositor,\r\n        bytes32 recipient,\r\n        bytes32 currency,\r\n        uint256 amount,\r\n        uint64 wormholeSequence\r\n     );\r\n\r\n    event TokenWithdrawn(\r\n        uint256 srcChainId,\r\n        uint256 destChainId,\r\n        uint256 depositId,\r\n        bytes32 depositor,\r\n        bytes32 recipient,\r\n        bytes32 currency,\r\n        uint256 amount\r\n    );\r\n\r\n    event TokenDeposited(\r\n        uint256 srcChainId,\r\n        uint256 destChainId,\r\n        bytes32 depositId,\r\n        address depositor,\r\n        address recipient,\r\n        bytes32 currency,\r\n        uint256 amount\r\n    );\r\n\r\n    event TokenWithdrawn(\r\n        uint256 srcChainId,\r\n        uint256 destChainId,\r\n        bytes32 depositId,\r\n        address depositor,\r\n        address recipient,\r\n        bytes32 currency,\r\n        uint256 amount\r\n    );\r\n\r\n    event TokenAdded(bytes32 tokenKey, address tokenAddress, uint8 lockType);\r\n    event TokenRemoved(bytes32 tokenKey);\r\n    event ChainSupportForTokenAdded(bytes32 tokenKey, uint256 chainId);\r\n    event ChainSupportForTokenDropped(bytes32 tokenKey, uint256 chainId);\r\n    event WormholeSetup(address coreContract, uint8 consistencyLevel);\r\n    event BridgeAddressForChainUpdated(uint256 chainId, address bridgeAddress);\r\n    event WormholeNetworkIdUpdated(uint256 chainId, uint16 wormholeNetworkId);\r\n    \r\n    struct TokenInfo {\r\n        address tokenAddress;\r\n        uint8 lockType;\r\n    }  \r\n\r\n    //.DEPRECATED\r\n    struct WormholeConfig {\r\n        IWormhole coreContract;\r\n        uint8 consistencyLevel;\r\n    }\r\n\r\n    modifier onlyWithdrawThroughMessageBroker(){ \r\n        require(msg.sender == address(erc20MessageBroker) && address(erc20MessageBroker) != address(0), \"Only registered message broker can withdraw\");\r\n        _;\r\n    }\r\n\r\n\r\n    uint256 public currentChainId;\r\n    address private DEPRECATED_DO_NOT_USE_0; //.DEPRECATED\r\n\r\n    uint256 public depositCount; //.DEPRECATED\r\n    mapping(bytes32 => TokenInfo) public tokenInfos;\r\n    mapping(bytes32 => mapping(uint256 => bool)) public tokenSupportedOnChain;\r\n    mapping(uint256 => mapping(uint256 => bool)) public withdrawnDeposits; //.DEPRECATED \r\n\r\n    bytes32 private DEPRECATED_DO_NOT_USE_1; //.DEPRECATED\r\n\r\n    WormholeConfig private wormhole; //.DEPRECATED\r\n    IErc20MessageBroker private erc20MessageBroker; //.ADDED  \r\n    mapping(uint256 => bytes32) public bridgeContractsByChainId; //.DEPRECATED\r\n    mapping(uint256 => uint16) public wormholeNetworkIdsByChainId; //.DEPRECATED\r\n\r\n    uint8 public constant TOKEN_LOCK_TYPE_TRANSFER = 1;\r\n    uint8 public constant TOKEN_LOCK_TYPE_MINT_BURN = 2;\r\n\r\n    bytes4 private constant TRANSFER_SELECTOR = bytes4(keccak256(bytes(\"transfer(address,uint256)\")));\r\n    bytes4 private constant TRANSFERFROM_SELECTOR = bytes4(keccak256(bytes(\"transferFrom(address,address,uint256)\")));\r\n\r\n    bool public paused;\r\n    modifier notPaused(){\r\n        require(msg.sender == admin || !paused, \"Contract is currently paused\");\r\n        _;\r\n    }\r\n\r\n    function unpause() external onlyAdmin{\r\n        paused = false;\r\n    }\r\n\r\n    function pause() external onlyAdmin{\r\n        paused = true;\r\n    }\r\n\r\n    function getTokenAddress(bytes32 tokenKey) public view returns (address) {\r\n        return tokenInfos[tokenKey].tokenAddress;\r\n    }\r\n\r\n    function getTokenLockType(bytes32 tokenKey) public view returns (uint8) {\r\n        return tokenInfos[tokenKey].lockType;\r\n    }\r\n\r\n    function isTokenSupportedOnChain(bytes32 tokenKey, uint256 chainId) public view returns (bool) {\r\n        return tokenSupportedOnChain[tokenKey][chainId];\r\n    }\r\n\r\n    function __LnErc20Bridge_init(address _admin) public initializer {\r\n        __LnAdminUpgradeable_init(_admin);\r\n\r\n        uint256 chainId;\r\n        assembly {\r\n            chainId := chainid()\r\n        }\r\n        currentChainId = chainId;\r\n    }\r\n    \r\n    function setUpCCIP(address _erc20MessageBroker) external onlyAdmin\r\n    {\r\n        erc20MessageBroker = IErc20MessageBroker(_erc20MessageBroker);\r\n    }\r\n\r\n    function addToken(\r\n        bytes32 tokenKey,\r\n        address tokenAddress,\r\n        uint8 lockType\r\n        \r\n    ) external onlyAdmin {\r\n        require(tokenAddress != address(0), \"LnErc20Bridge: zero address\");\r\n        require(\r\n            lockType == TOKEN_LOCK_TYPE_TRANSFER || lockType == TOKEN_LOCK_TYPE_MINT_BURN,\r\n            \"LnErc20Bridge: unknown token lock type\"\r\n        );\r\n\r\n        tokenInfos[tokenKey] = TokenInfo({tokenAddress: tokenAddress, lockType: lockType});\r\n        emit TokenAdded(tokenKey, tokenAddress, lockType);\r\n    }\r\n\r\n    function removeToken(bytes32 tokenKey) external onlyAdmin {\r\n        require(tokenInfos[tokenKey].tokenAddress != address(0), \"LnErc20Bridge: token does not exists\");\r\n        delete tokenInfos[tokenKey];\r\n        emit TokenRemoved(tokenKey);\r\n    }\r\n\r\n    function addChainSupportForToken(bytes32 tokenKey, uint256 chainId) external onlyAdmin {\r\n        require(!tokenSupportedOnChain[tokenKey][chainId], \"LnErc20Bridge: already supported\");\r\n        tokenSupportedOnChain[tokenKey][chainId] = true;\r\n        emit ChainSupportForTokenAdded(tokenKey, chainId);\r\n    }\r\n\r\n    function dropChainSupportForToken(bytes32 tokenKey, uint256 chainId) external onlyAdmin {\r\n        require(tokenSupportedOnChain[tokenKey][chainId], \"LnErc20Bridge: not supported\");\r\n        tokenSupportedOnChain[tokenKey][chainId] = false;\r\n        emit ChainSupportForTokenDropped(tokenKey, chainId);\r\n    }\r\n\r\n    function deposit(\r\n        bytes32 token,\r\n        uint256 amount,\r\n        uint64 destChainId,\r\n        address recipient\r\n    ) external payable notPaused {\r\n        TokenInfo memory tokenInfo = tokenInfos[token];\r\n        require(tokenInfo.tokenAddress != address(0), \"LnErc20Bridge: token not found\");\r\n        require(amount > 0, \"LnErc20Bridge: amount must be positive\");\r\n        require(destChainId != currentChainId, \"LnErc20Bridge: dest must be different from src\");\r\n        require(isTokenSupportedOnChain(token, destChainId), \"LnErc20Bridge: token not supported on chain\");\r\n        require(recipient != address(0), \"LnErc20Bridge: zero address\");\r\n        if (tokenInfo.lockType == TOKEN_LOCK_TYPE_TRANSFER) {\r\n            safeTransferFrom(tokenInfo.tokenAddress, msg.sender, address(this), amount);\r\n        } else if (tokenInfo.lockType == TOKEN_LOCK_TYPE_MINT_BURN) {\r\n            IMintBurnToken(tokenInfo.tokenAddress).burn(msg.sender, amount);\r\n        } else {\r\n            require(false, \"LnErc20Bridge: unknown token lock type\");\r\n        }       \r\n        uint256 estimatedTotalCost = erc20MessageBroker.getFee(token, amount, destChainId, recipient); \r\n        require(msg.value >= estimatedTotalCost, \"Insufficient funds sent\");\r\n        // Send the CCIP message through the router and store the returned CCIP message ID\r\n        bytes32 messageId = erc20MessageBroker.sendMessage{value: msg.value}(token, amount, destChainId, msg.sender, recipient); \r\n        emit TokenDeposited(\r\n            currentChainId,\r\n            destChainId,\r\n            messageId,\r\n            msg.sender,\r\n            recipient,\r\n            token,\r\n            amount\r\n        );\r\n    }\r\n\r\n    function withdraw(\r\n            bytes32 messageId,\r\n            uint256 srcChainId,\r\n            uint256 destChainId,\r\n            address depositor,\r\n            address recipient,\r\n            bytes32 currency,\r\n            uint256 amount) external onlyWithdrawThroughMessageBroker\r\n    {\r\n        TokenInfo memory tokenInfo = tokenInfos[currency];\r\n        require(tokenInfo.tokenAddress != address(0), \"LnErc20Bridge: token not found\");        \r\n        // Transfer the required funds to the destination if the bridge is configured as 'TOKEN_LOCK_TYPE_TRANSFER' and therefore the funds are retrievable on the contract\r\n        if (tokenInfo.lockType == TOKEN_LOCK_TYPE_TRANSFER) {\r\n            safeTransfer(tokenInfo.tokenAddress, recipient, amount);\r\n        } \r\n        // Mint the required funds to the destination if the bridge is configured as 'TOKEN_LOCK_TYPE_MINT_BURN'\r\n        else if (tokenInfo.lockType == TOKEN_LOCK_TYPE_MINT_BURN) {\r\n            IMintBurnToken(tokenInfo.tokenAddress).mint(recipient, amount);\r\n        } else {\r\n            require(false, \"LnErc20Bridge: unknown token lock type\");\r\n        }\r\n        emit TokenWithdrawn(srcChainId, destChainId, messageId, depositor, recipient, currency, amount);\r\n    }\r\n\r\n    function safeTransfer(\r\n        address token,\r\n        address recipient,\r\n        uint256 amount\r\n    ) private {\r\n        (bool success, bytes memory data) = token.call(abi.encodeWithSelector(TRANSFER_SELECTOR, recipient, amount));\r\n        require(success && (data.length == 0 || abi.decode(data, (bool))), \"LnErc20Bridge: transfer failed\");\r\n    }\r\n\r\n    function safeTransferFrom(\r\n        address token,\r\n        address sender,\r\n        address recipient,\r\n        uint256 amount\r\n    ) private {\r\n        (bool success, bytes memory data) = \r\n            token.call(abi.encodeWithSelector(TRANSFERFROM_SELECTOR, sender, recipient, amount));\r\n        require(success && (data.length == 0 || abi.decode(data, (bool))), \"LnErc20Bridge: transfer from failed\");\r\n    }\r\n    uint256[46] private __gap;\r\n}"
      },
      "contracts/upgradeable/LnAdminUpgradeable.sol": {
        "content": "// SPDX-License-Identifier: MIT\r\npragma solidity >=0.6.12 <0.8.0;\r\n\r\nimport \"@openzeppelin/contracts-upgradeable/proxy/Initializable.sol\";\r\nimport {LnAdminableContract} from \"../LnAdminableContract.sol\";\r\n\r\n/**\r\n * @title LnAdminUpgradeable\r\n *\r\n * @dev This is an upgradeable version of `LnAdmin` by replacing the constructor with\r\n * an initializer and reserving storage slots.\r\n */\r\ncontract LnAdminUpgradeable is Initializable, LnAdminableContract {    \r\n    function __LnAdminUpgradeable_init(address _admin) public initializer {\r\n        require(_admin != address(0), \"LnAdminUpgradeable: zero address\");\r\n        admin = _admin;\r\n        emit AdminChanged(address(0), _admin);\r\n    }\r\n    // Reserved storage space to allow for layout changes in the future.\r\n    uint256[48] private __gap;\r\n}\r\n"
      }
    },
    "settings": {
      "optimizer": {
        "enabled": true,
        "runs": 200
      },
      "outputSelection": {
        "*": {
          "*": [
            "evm.bytecode",
            "evm.deployedBytecode",
            "devdoc",
            "userdoc",
            "metadata",
            "abi"
          ]
        }
      },
      "libraries": {}
    }
  }}