creation_sourcecode: {{
    "language": "Solidity",
    "sources": {
      "src/CCIPxERC20Bridge.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.19;\n\nimport {CCIPReceiver} from \"ccip/src/v0.8/ccip/applications/CCIPReceiver.sol\";\nimport {IRouterClient} from \"ccip/src/v0.8/ccip/interfaces/IRouterClient.sol\";\nimport {Client} from \"ccip/src/v0.8/ccip/libraries/Client.sol\";\nimport {OwnerIsCreator} from \"ccip/src/v0.8/shared/access/OwnerIsCreator.sol\";\nimport {IERC20} from \"ccip/src/v0.8/vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/IERC20.sol\";\nimport {IXERC20} from \"xERC20/solidity/interfaces/IXERC20.sol\";\nimport {IXERC20Lockbox} from \"xERC20/solidity/interfaces/IXERC20Lockbox.sol\";\n\n/**\n * THIS IS AN EXAMPLE CONTRACT THAT USES HARDCODED VALUES FOR CLARITY.\n * THIS IS AN EXAMPLE CONTRACT THAT USES UN-AUDITED CODE.\n * DO NOT USE THIS CODE IN PRODUCTION.\n */\n\n/// @title - A simple messenger contract for sending/receving string data across chains.\ncontract CCIPxERC20Bridge is CCIPReceiver, OwnerIsCreator {\n    // Custom errors to provide more descriptive revert messages.\n    error NotEnoughBalance(uint256 currentBalance, uint256 calculatedFees); // Used to make sure contract has enough balance.\n    error NothingToWithdraw(); // Used when trying to withdraw Ether but there's nothing to withdraw.\n    error FailedToWithdrawEth(address owner, address target, uint256 value); // Used when the withdrawal of Ether fails.\n    error SenderNotAllowlistedBySourceChain(\n        uint64 sourceChainSelector,\n        address sender\n    ); // Used when the sender has not been allowlisted by the contract owner.\n    error NoReceiverForDestinationChain(uint64 destinationChainSelector); // Used when the receiver has not been allowlisted by the contract owner.\n\n    // Event emitted when a message is sent to another chain.\n    event MessageSent(\n        // The unique ID of the CCIP message.\n        bytes32 indexed messageId,\n        uint64 indexed destinationChainSelector,\n        address receiver,\n        address recipient,\n        uint256 amount,\n        address feeToken,\n        uint256 fees\n    );\n\n    // Event emitted when a message is received from another chain.\n    event MessageReceived(\n        // The unique ID of the CCIP message.\n        // The chain selector of the source chain.\n        // The address of the sender from the source chain.\n        // The text that was received.\n        bytes32 indexed messageId,\n        uint64 indexed sourceChainSelector,\n        address sender,\n        uint256 amount,\n        address recipient\n    );\n\n    bytes32 private _lastReceivedMessageId; // Store the last received messageId.\n    string private _lastReceivedText; // Store the last received text.\n\n    // Mapping to keep track of allowlisted senders by source chain.\n    mapping(uint64 => address) public bridgesByChain;\n\n    IERC20 public linkToken;\n\n    struct XERC20Config {\n        IERC20 erc20;\n        IXERC20Lockbox lockbox;\n    }\n\n    mapping(IXERC20 => XERC20Config) public xerc20s;\n\n    mapping(uint64 => mapping(address => address)) public xerc20sByChain;\n\n    mapping(uint32 => uint64) public chainIdToChainSelector;\n\n    uint256 public feeBps; // fee in basis pts, i.e. 10 = 0.1%\n\n    /// @notice Constructor initializes the contract with the router address.\n    /// @param _router The address of the router contract.\n    /// @param _link The address of the link contract.\n    constructor(\n        address _router,\n        address _link,\n        uint256 _feeBps\n    ) CCIPReceiver(_router) {\n        linkToken = IERC20(_link);\n        feeBps = _feeBps;\n\n        // testnets\n        chainIdToChainSelector[11_155_111] = 16_015_286_601_757_825_753;\n        chainIdToChainSelector[421_614] = 3_478_487_238_524_512_106;\n        chainIdToChainSelector[80_001] = 12_532_609_583_862_916_517;\n\n        // mainnets\n        chainIdToChainSelector[1] = 5_009_297_550_715_157_269;\n        chainIdToChainSelector[10] = 3_734_403_246_176_062_136;\n        chainIdToChainSelector[56] = 11_344_663_589_394_136_015;\n        chainIdToChainSelector[137] = 4_051_577_828_743_386_545;\n        chainIdToChainSelector[8453] = 15_971_525_489_660_198_786;\n        chainIdToChainSelector[43_114] = 6_433_500_567_565_415_381;\n        chainIdToChainSelector[42_161] = 4_949_039_107_694_359_620;\n    }\n\n    /// @dev Modifier to make a function callable only when the sender is allowlisted by the contract owner.\n    modifier onlyAllowlistedSenderBySourceChain(\n        uint64 _sourceChainSelector,\n        address _sender\n    ) {\n        if (bridgesByChain[_sourceChainSelector] != _sender) {\n            revert SenderNotAllowlistedBySourceChain(\n                _sourceChainSelector,\n                _sender\n            );\n        }\n        _;\n    }\n\n    modifier validReceiver(uint64 _destinationChainSelector) {\n        if (bridgesByChain[_destinationChainSelector] == address(0)) {\n            revert NoReceiverForDestinationChain(_destinationChainSelector);\n        }\n        _;\n    }\n\n    function addXERC20ForOriginChain(\n        uint64 _chainSelector,\n        address _xerc20remote,\n        address _xerc20local\n    ) external onlyOwner {\n        xerc20sByChain[_chainSelector][_xerc20remote] = _xerc20local;\n    }\n\n    function addXERC20Config(\n        IXERC20 _xerc20,\n        IERC20 _erc20,\n        IXERC20Lockbox _lockbox\n    ) external onlyOwner {\n        xerc20s[IXERC20(_xerc20)] = XERC20Config({\n            erc20: IERC20(_erc20),\n            lockbox: IXERC20Lockbox(_lockbox)\n        });\n    }\n\n    function addBridgeForChain(\n        uint64 _chainSelector,\n        address _bridge\n    ) external onlyOwner {\n        bridgesByChain[_chainSelector] = _bridge;\n    }\n\n    function addChainIdToChainSelector(\n        uint32 _chainId,\n        uint64 _chainSelector\n    ) external onlyOwner {\n        chainIdToChainSelector[_chainId] = _chainSelector;\n    }\n\n    function setFeeBps(uint256 _feeBps) external onlyOwner {\n        feeBps = _feeBps;\n    }\n\n    function getFee(\n        address _xerc20,\n        uint32 _destinationChainId,\n        uint256 _amount,\n        bool _feeInLINK\n    ) external view returns (uint256) {\n        uint64 _destinationChainSelector = chainIdToChainSelector[\n            _destinationChainId\n        ];\n        address _receiver = bridgesByChain[_destinationChainSelector];\n        IRouterClient router = IRouterClient(this.getRouter());\n        Client.EVM2AnyMessage memory evm2AnyMessage = _buildCCIPMessage(\n            _xerc20,\n            _receiver,\n            _amount,\n            msg.sender,\n            _feeInLINK ? address(linkToken) : address(0)\n        );\n        return router.getFee(_destinationChainSelector, evm2AnyMessage);\n    }\n\n    function bridgeTokens(\n        address _xerc20,\n        uint32 _destinationChainId,\n        address _receipient,\n        uint256 _amount\n    ) external payable returns (bytes32 messageId) {\n        return\n            _bridgeTokens(\n                _xerc20,\n                _destinationChainId,\n                _receipient,\n                _amount,\n                false\n            );\n    }\n\n    function bridgeTokensWithLINK(\n        address _xerc20,\n        uint32 _destinationChainId,\n        address _receipient,\n        uint256 _amount\n    ) external returns (bytes32 messageId) {\n        return\n            _bridgeTokens(\n                _xerc20,\n                _destinationChainId,\n                _receipient,\n                _amount,\n                true\n            );\n    }\n\n    function _bridgeTokens(\n        address _xerc20,\n        uint32 _destinationChainId,\n        address _receipient,\n        uint256 _amount,\n        bool _feeInLINK\n    )\n        internal\n        validReceiver(chainIdToChainSelector[_destinationChainId])\n        returns (bytes32 messageId)\n    {\n        uint64 _destinationChainSelector = chainIdToChainSelector[\n            _destinationChainId\n        ];\n        address _receiver = bridgesByChain[_destinationChainSelector];\n\n        if (address(xerc20s[IXERC20(_xerc20)].lockbox) == address(0)) {\n            // no lockbox, use xerc20 directly\n            IERC20(address(_xerc20)).transferFrom(\n                msg.sender,\n                address(this),\n                _amount\n            );\n        } else {\n            // transfer erc20 here then lock it in lockbox\n            xerc20s[IXERC20(_xerc20)].erc20.transferFrom(\n                msg.sender,\n                address(this),\n                _amount\n            );\n            xerc20s[IXERC20(_xerc20)].erc20.approve(\n                address(xerc20s[IXERC20(_xerc20)].lockbox),\n                _amount\n            );\n            // deposit to lockbox\n            xerc20s[IXERC20(_xerc20)].lockbox.deposit(_amount);\n            // xerc20 will be minted to this contract\n        }\n\n        // Burn the tokens minus the fee\n        uint256 _bridgedAmount = _amount - ((_amount * feeBps) / 10_000);\n        IXERC20(_xerc20).burn(address(this), _bridgedAmount);\n\n        address _feeToken = _feeInLINK ? address(linkToken) : address(0);\n\n        // Create an EVM2AnyMessage struct in memory with necessary information for sending a cross-chain message\n        Client.EVM2AnyMessage memory evm2AnyMessage = _buildCCIPMessage(\n            _xerc20,\n            _receiver,\n            _bridgedAmount,\n            _receipient,\n            _feeToken\n        );\n\n        // Initialize a router client instance to interact with cross-chain router\n        IRouterClient router = IRouterClient(this.getRouter());\n\n        // Get the fee required to send the CCIP message\n        uint256 fees = router.getFee(_destinationChainSelector, evm2AnyMessage);\n\n        if (_feeInLINK) {\n            linkToken.transferFrom(msg.sender, address(this), fees);\n            linkToken.approve(address(router), fees);\n        } else {\n            if (msg.value < fees) {\n                revert NotEnoughBalance(address(this).balance, fees);\n            }\n            uint256 _refund = msg.value - fees;\n            if (_refund > 0) {\n                payable(msg.sender).transfer(_refund);\n            }\n        }\n        // Send the CCIP message through the router and store the returned CCIP message ID\n        messageId = router.ccipSend{value: _feeInLINK ? 0 : fees}(\n            _destinationChainSelector,\n            evm2AnyMessage\n        );\n\n        // Emit an event with message details\n        emit MessageSent(\n            messageId,\n            _destinationChainSelector,\n            _receiver,\n            _receipient,\n            _bridgedAmount,\n            _feeToken,\n            fees\n        );\n\n        // Return the CCIP message ID\n        return messageId;\n    }\n\n    /// handle a received message\n    function _ccipReceive(\n        Client.Any2EVMMessage memory any2EvmMessage\n    )\n        internal\n        override\n        onlyAllowlistedSenderBySourceChain(\n            any2EvmMessage.sourceChainSelector,\n            abi.decode(any2EvmMessage.sender, (address))\n        ) // Make sure source chain and sender are allowlisted\n    {\n        _lastReceivedMessageId = any2EvmMessage.messageId; // fetch the messageId\n        (address _xerc20, uint256 _amount, address _recipient) = abi.decode(\n            any2EvmMessage.data,\n            (address, uint256, address)\n        ); // abi-decoding of the sent text\n\n        address localXERC20 = xerc20sByChain[\n            any2EvmMessage.sourceChainSelector\n        ][address(_xerc20)];\n\n        XERC20Config memory xerc20Config = xerc20s[IXERC20(localXERC20)];\n\n        if (address(xerc20Config.lockbox) == address(0)) {            // no lockbox, mint directly to recipient\n            IXERC20(localXERC20).mint(_recipient, _amount);\n\n        } else {            // withdraw from lockbox\n            // mint to this contract\n            IXERC20(localXERC20).mint(address(this), _amount);\n            // withdraw from lockbox, erc20 will be transferred to this contract\n            xerc20Config.lockbox.withdraw(_amount);\n            // transfer erc20s to recipient\n            IERC20(address(xerc20Config.erc20)).transfer(_recipient, _amount);\n        }\n\n        emit MessageReceived(\n            any2EvmMessage.messageId,\n            any2EvmMessage.sourceChainSelector, // fetch the source chain identifier (aka selector)\n            abi.decode(any2EvmMessage.sender, (address)), // abi-decoding of the sender address,\n            _amount,\n            _recipient\n        );\n    }\n\n    /// @notice Construct a CCIP message.\n    /// @dev This function will create an EVM2AnyMessage struct with all the necessary information for sending a text.\n    /// @param _receiver The address of the receiver on the destination chain.\n    /// @param _amount The amount of tokens to be transferred.\n    /// @param _receipient The address of the receipient on the destination chain.\n    /// @param _feeTokenAddress The address of the token to be used for paying fees.\n    function _buildCCIPMessage(\n        address _xerc20,\n        address _receiver,\n        uint256 _amount,\n        address _receipient,\n        address _feeTokenAddress\n    ) internal pure returns (Client.EVM2AnyMessage memory) {\n        // Create an EVM2AnyMessage struct in memory with necessary information for sending a cross-chain message\n        return\n            Client.EVM2AnyMessage({\n                receiver: abi.encode(_receiver), // ABI-encoded receiver address\n                data: abi.encode(_xerc20, _amount, _receipient), // ABI-encoded string\n                tokenAmounts: new Client.EVMTokenAmount[](0), // Empty array aas no tokens are transferred\n                extraArgs: Client._argsToBytes(\n                    // Additional arguments, setting gas limit\n                    Client.EVMExtraArgsV1({gasLimit: 200_000})\n                ),\n                // Set the feeToken to a feeTokenAddress, indicating specific asset will be used for fees\n                feeToken: _feeTokenAddress\n            });\n    }\n\n    /// @notice Fetches the details of the last received message.\n    /// @return messageId The ID of the last received message.\n    /// @return text The last received text.\n    function getLastReceivedMessageDetails()\n        external\n        view\n        returns (bytes32 messageId, string memory text)\n    {\n        return (_lastReceivedMessageId, _lastReceivedText);\n    }\n\n    /// @notice Fallback function to allow the contract to receive Ether.\n    /// @dev This function has no function body, making it a default function for receiving Ether.\n    /// It is automatically called when Ether is sent to the contract without any data.\n    receive() external payable {}\n\n    /// @notice Allows the contract owner to withdraw the entire balance of Ether from the contract.\n    /// @dev This function reverts if there are no funds to withdraw or if the transfer fails.\n    /// It should only be callable by the owner of the contract.\n    /// @param _beneficiary The address to which the Ether should be sent.\n    function withdraw(address _beneficiary) public onlyOwner {\n        // Retrieve the balance of this contract\n        uint256 amount = address(this).balance;\n\n        // Revert if there is nothing to withdraw\n        if (amount == 0) revert NothingToWithdraw();\n\n        // Attempt to send the funds, capturing the success status and discarding any return data\n        (bool sent, ) = _beneficiary.call{value: amount}(\"\");\n\n        // Revert if the send failed, with information about the attempted transfer\n        if (!sent) revert FailedToWithdrawEth(msg.sender, _beneficiary, amount);\n    }\n\n    /// @notice Allows the owner of the contract to withdraw all tokens of a specific ERC20 token.\n    /// @dev This function reverts with a 'NothingToWithdraw' error if there are no tokens to withdraw.\n    /// @param _beneficiary The address to which the tokens will be sent.\n    /// @param _token The contract address of the ERC20 token to be withdrawn.\n    function withdrawToken(\n        address _beneficiary,\n        address _token\n    ) public onlyOwner {\n        // Retrieve the balance of this contract\n        uint256 amount = IERC20(_token).balanceOf(address(this));\n\n        // Revert if there is nothing to withdraw\n        if (amount == 0) revert NothingToWithdraw();\n\n        IERC20(_token).transfer(_beneficiary, amount);\n    }\n}\n"
      },
      "lib/ccip/contracts/src/v0.8/ccip/applications/CCIPReceiver.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {IAny2EVMMessageReceiver} from \"../interfaces/IAny2EVMMessageReceiver.sol\";\n\nimport {Client} from \"../libraries/Client.sol\";\n\nimport {IERC165} from \"../../vendor/openzeppelin-solidity/v4.8.3/contracts/utils/introspection/IERC165.sol\";\n\n/// @title CCIPReceiver - Base contract for CCIP applications that can receive messages.\nabstract contract CCIPReceiver is IAny2EVMMessageReceiver, IERC165 {\n  address internal immutable i_ccipRouter;\n\n  constructor(address router) {\n    if (router == address(0)) revert InvalidRouter(address(0));\n    i_ccipRouter = router;\n  }\n\n  /// @notice IERC165 supports an interfaceId\n  /// @param interfaceId The interfaceId to check\n  /// @return true if the interfaceId is supported\n  /// @dev Should indicate whether the contract implements IAny2EVMMessageReceiver\n  /// e.g. return interfaceId == type(IAny2EVMMessageReceiver).interfaceId || interfaceId == type(IERC165).interfaceId\n  /// This allows CCIP to check if ccipReceive is available before calling it.\n  /// If this returns false or reverts, only tokens are transferred to the receiver.\n  /// If this returns true, tokens are transferred and ccipReceive is called atomically.\n  /// Additionally, if the receiver address does not have code associated with\n  /// it at the time of execution (EXTCODESIZE returns 0), only tokens will be transferred.\n  function supportsInterface(bytes4 interfaceId) public pure virtual override returns (bool) {\n    return interfaceId == type(IAny2EVMMessageReceiver).interfaceId || interfaceId == type(IERC165).interfaceId;\n  }\n\n  /// @inheritdoc IAny2EVMMessageReceiver\n  function ccipReceive(Client.Any2EVMMessage calldata message) external virtual override onlyRouter {\n    _ccipReceive(message);\n  }\n\n  /// @notice Override this function in your implementation.\n  /// @param message Any2EVMMessage\n  function _ccipReceive(Client.Any2EVMMessage memory message) internal virtual;\n\n  /////////////////////////////////////////////////////////////////////\n  // Plumbing\n  /////////////////////////////////////////////////////////////////////\n\n  /// @notice Return the current router\n  /// @return CCIP router address\n  function getRouter() public view returns (address) {\n    return address(i_ccipRouter);\n  }\n\n  error InvalidRouter(address router);\n\n  /// @dev only calls from the set router are accepted.\n  modifier onlyRouter() {\n    if (msg.sender != address(i_ccipRouter)) revert InvalidRouter(msg.sender);\n    _;\n  }\n}\n"
      },
      "lib/ccip/contracts/src/v0.8/ccip/interfaces/IRouterClient.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {Client} from \"../libraries/Client.sol\";\n\ninterface IRouterClient {\n  error UnsupportedDestinationChain(uint64 destChainSelector);\n  error InsufficientFeeTokenAmount();\n  error InvalidMsgValue();\n\n  /// @notice Checks if the given chain ID is supported for sending/receiving.\n  /// @param chainSelector The chain to check.\n  /// @return supported is true if it is supported, false if not.\n  function isChainSupported(uint64 chainSelector) external view returns (bool supported);\n\n  /// @notice Gets a list of all supported tokens which can be sent or received\n  /// to/from a given chain id.\n  /// @param chainSelector The chainSelector.\n  /// @return tokens The addresses of all tokens that are supported.\n  function getSupportedTokens(uint64 chainSelector) external view returns (address[] memory tokens);\n\n  /// @param destinationChainSelector The destination chainSelector\n  /// @param message The cross-chain CCIP message including data and/or tokens\n  /// @return fee returns execution fee for the message\n  /// delivery to destination chain, denominated in the feeToken specified in the message.\n  /// @dev Reverts with appropriate reason upon invalid message.\n  function getFee(\n    uint64 destinationChainSelector,\n    Client.EVM2AnyMessage memory message\n  ) external view returns (uint256 fee);\n\n  /// @notice Request a message to be sent to the destination chain\n  /// @param destinationChainSelector The destination chain ID\n  /// @param message The cross-chain CCIP message including data and/or tokens\n  /// @return messageId The message ID\n  /// @dev Note if msg.value is larger than the required fee (from getFee) we accept\n  /// the overpayment with no refund.\n  /// @dev Reverts with appropriate reason upon invalid message.\n  function ccipSend(\n    uint64 destinationChainSelector,\n    Client.EVM2AnyMessage calldata message\n  ) external payable returns (bytes32);\n}\n"
      },
      "lib/ccip/contracts/src/v0.8/ccip/libraries/Client.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n// End consumer library.\nlibrary Client {\n  /// @dev RMN depends on this struct, if changing, please notify the RMN maintainers.\n  struct EVMTokenAmount {\n    address token; // token address on the local chain.\n    uint256 amount; // Amount of tokens.\n  }\n\n  struct Any2EVMMessage {\n    bytes32 messageId; // MessageId corresponding to ccipSend on source.\n    uint64 sourceChainSelector; // Source chain selector.\n    bytes sender; // abi.decode(sender) if coming from an EVM chain.\n    bytes data; // payload sent in original message.\n    EVMTokenAmount[] destTokenAmounts; // Tokens and their amounts in their destination chain representation.\n  }\n\n  // If extraArgs is empty bytes, the default is 200k gas limit.\n  struct EVM2AnyMessage {\n    bytes receiver; // abi.encode(receiver address) for dest EVM chains\n    bytes data; // Data payload\n    EVMTokenAmount[] tokenAmounts; // Token transfers\n    address feeToken; // Address of feeToken. address(0) means you will send msg.value.\n    bytes extraArgs; // Populate this with _argsToBytes(EVMExtraArgsV1)\n  }\n\n  // bytes4(keccak256(\"CCIP EVMExtraArgsV1\"));\n  bytes4 public constant EVM_EXTRA_ARGS_V1_TAG = 0x97a657c9;\n  struct EVMExtraArgsV1 {\n    uint256 gasLimit;\n  }\n\n  function _argsToBytes(EVMExtraArgsV1 memory extraArgs) internal pure returns (bytes memory bts) {\n    return abi.encodeWithSelector(EVM_EXTRA_ARGS_V1_TAG, extraArgs);\n  }\n}\n"
      },
      "lib/ccip/contracts/src/v0.8/shared/access/OwnerIsCreator.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {ConfirmedOwner} from \"./ConfirmedOwner.sol\";\n\n/// @title The OwnerIsCreator contract\n/// @notice A contract with helpers for basic contract ownership.\ncontract OwnerIsCreator is ConfirmedOwner {\n  constructor() ConfirmedOwner(msg.sender) {}\n}\n"
      },
      "lib/ccip/contracts/src/v0.8/vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/IERC20.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\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  /**\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 `to`.\n   *\n   * Returns a boolean value indicating whether the operation succeeded.\n   *\n   * Emits a {Transfer} event.\n   */\n  function transfer(address to, 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 `from` to `to` 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(address from, address to, uint256 amount) external returns (bool);\n}\n"
      },
      "lib/xERC20/solidity/interfaces/IXERC20.sol": {
        "content": "// SPDX-License-Identifier: UNLICENSED\npragma solidity >=0.8.4 <0.9.0;\n\ninterface IXERC20 {\n  /**\n   * @notice Emits when a lockbox is set\n   *\n   * @param _lockbox The address of the lockbox\n   */\n  event LockboxSet(address _lockbox);\n\n  /**\n   * @notice Emits when a limit is set\n   *\n   * @param _mintingLimit The updated minting limit we are setting to the bridge\n   * @param _burningLimit The updated burning limit we are setting to the bridge\n   * @param _bridge The address of the bridge we are setting the limit too\n   */\n  event BridgeLimitsSet(uint256 _mintingLimit, uint256 _burningLimit, address indexed _bridge);\n\n  /**\n   * @notice Reverts when a user with too low of a limit tries to call mint/burn\n   */\n  error IXERC20_NotHighEnoughLimits();\n\n  /**\n   * @notice Reverts when caller is not the factory\n   */\n  error IXERC20_NotFactory();\n\n  /**\n   * @notice Reverts when limits are too high\n   */\n  error IXERC20_LimitsTooHigh();\n\n  /**\n   * @notice Contains the full minting and burning data for a particular bridge\n   *\n   * @param minterParams The minting parameters for the bridge\n   * @param burnerParams The burning parameters for the bridge\n   */\n  struct Bridge {\n    BridgeParameters minterParams;\n    BridgeParameters burnerParams;\n  }\n\n  /**\n   * @notice Contains the mint or burn parameters for a bridge\n   *\n   * @param timestamp The timestamp of the last mint/burn\n   * @param ratePerSecond The rate per second of the bridge\n   * @param maxLimit The max limit of the bridge\n   * @param currentLimit The current limit of the bridge\n   */\n  struct BridgeParameters {\n    uint256 timestamp;\n    uint256 ratePerSecond;\n    uint256 maxLimit;\n    uint256 currentLimit;\n  }\n\n  /**\n   * @notice Sets the lockbox address\n   *\n   * @param _lockbox The address of the lockbox\n   */\n  function setLockbox(address _lockbox) external;\n\n  /**\n   * @notice Updates the limits of any bridge\n   * @dev Can only be called by the owner\n   * @param _mintingLimit The updated minting limit we are setting to the bridge\n   * @param _burningLimit The updated burning limit we are setting to the bridge\n   * @param _bridge The address of the bridge we are setting the limits too\n   */\n  function setLimits(address _bridge, uint256 _mintingLimit, uint256 _burningLimit) external;\n\n  /**\n   * @notice Returns the max limit of a minter\n   *\n   * @param _minter The minter we are viewing the limits of\n   *  @return _limit The limit the minter has\n   */\n  function mintingMaxLimitOf(address _minter) external view returns (uint256 _limit);\n\n  /**\n   * @notice Returns the max limit of a bridge\n   *\n   * @param _bridge the bridge we are viewing the limits of\n   * @return _limit The limit the bridge has\n   */\n  function burningMaxLimitOf(address _bridge) external view returns (uint256 _limit);\n\n  /**\n   * @notice Returns the current limit of a minter\n   *\n   * @param _minter The minter we are viewing the limits of\n   * @return _limit The limit the minter has\n   */\n  function mintingCurrentLimitOf(address _minter) external view returns (uint256 _limit);\n\n  /**\n   * @notice Returns the current limit of a bridge\n   *\n   * @param _bridge the bridge we are viewing the limits of\n   * @return _limit The limit the bridge has\n   */\n  function burningCurrentLimitOf(address _bridge) external view returns (uint256 _limit);\n\n  /**\n   * @notice Mints tokens for a user\n   * @dev Can only be called by a minter\n   * @param _user The address of the user who needs tokens minted\n   * @param _amount The amount of tokens being minted\n   */\n  function mint(address _user, uint256 _amount) external;\n\n  /**\n   * @notice Burns tokens for a user\n   * @dev Can only be called by a minter\n   * @param _user The address of the user who needs tokens burned\n   * @param _amount The amount of tokens being burned\n   */\n  function burn(address _user, uint256 _amount) external;\n}\n"
      },
      "lib/xERC20/solidity/interfaces/IXERC20Lockbox.sol": {
        "content": "// SPDX-License-Identifier: UNLICENSED\npragma solidity >=0.8.4 <0.9.0;\n\ninterface IXERC20Lockbox {\n  /**\n   * @notice Emitted when tokens are deposited into the lockbox\n   *\n   * @param _sender The address of the user who deposited\n   * @param _amount The amount of tokens deposited\n   */\n\n  event Deposit(address _sender, uint256 _amount);\n\n  /**\n   * @notice Emitted when tokens are withdrawn from the lockbox\n   *\n   * @param _sender The address of the user who withdrew\n   * @param _amount The amount of tokens withdrawn\n   */\n\n  event Withdraw(address _sender, uint256 _amount);\n\n  /**\n   * @notice Reverts when a user tries to deposit native tokens on a non-native lockbox\n   */\n\n  error IXERC20Lockbox_NotNative();\n\n  /**\n   * @notice Reverts when a user tries to deposit non-native tokens on a native lockbox\n   */\n\n  error IXERC20Lockbox_Native();\n\n  /**\n   * @notice Reverts when a user tries to withdraw and the call fails\n   */\n\n  error IXERC20Lockbox_WithdrawFailed();\n\n  /**\n   * @notice Deposit ERC20 tokens into the lockbox\n   *\n   * @param _amount The amount of tokens to deposit\n   */\n\n  function deposit(uint256 _amount) external;\n\n  /**\n   * @notice Deposit ERC20 tokens into the lockbox, and send the XERC20 to a user\n   *\n   * @param _user The user to send the XERC20 to\n   * @param _amount The amount of tokens to deposit\n   */\n\n  function depositTo(address _user, uint256 _amount) external;\n\n  /**\n   * @notice Deposit the native asset into the lockbox, and send the XERC20 to a user\n   *\n   * @param _user The user to send the XERC20 to\n   */\n\n  function depositNativeTo(address _user) external payable;\n\n  /**\n   * @notice Withdraw ERC20 tokens from the lockbox\n   *\n   * @param _amount The amount of tokens to withdraw\n   */\n\n  function withdraw(uint256 _amount) external;\n\n  /**\n   * @notice Withdraw ERC20 tokens from the lockbox\n   *\n   * @param _user The user to withdraw to\n   * @param _amount The amount of tokens to withdraw\n   */\n\n  function withdrawTo(address _user, uint256 _amount) external;\n}\n"
      },
      "lib/ccip/contracts/src/v0.8/ccip/interfaces/IAny2EVMMessageReceiver.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {Client} from \"../libraries/Client.sol\";\n\n/// @notice Application contracts that intend to receive messages from\n/// the router should implement this interface.\ninterface IAny2EVMMessageReceiver {\n  /// @notice Called by the Router to deliver a message.\n  /// If this reverts, any token transfers also revert. The message\n  /// will move to a FAILED state and become available for manual execution.\n  /// @param message CCIP Message\n  /// @dev Note ensure you check the msg.sender is the OffRampRouter\n  function ccipReceive(Client.Any2EVMMessage calldata message) external;\n}\n"
      },
      "lib/ccip/contracts/src/v0.8/vendor/openzeppelin-solidity/v4.8.3/contracts/utils/introspection/IERC165.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n    /**\n     * @dev Returns true if this contract implements the interface defined by\n     * `interfaceId`. See the corresponding\n     * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n     * to learn more about how these ids are created.\n     *\n     * This function call must use less than 30 000 gas.\n     */\n    function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}"
      },
      "lib/ccip/contracts/src/v0.8/shared/access/ConfirmedOwner.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {ConfirmedOwnerWithProposal} from \"./ConfirmedOwnerWithProposal.sol\";\n\n/// @title The ConfirmedOwner contract\n/// @notice A contract with helpers for basic contract ownership.\ncontract ConfirmedOwner is ConfirmedOwnerWithProposal {\n  constructor(address newOwner) ConfirmedOwnerWithProposal(newOwner, address(0)) {}\n}\n"
      },
      "lib/ccip/contracts/src/v0.8/shared/access/ConfirmedOwnerWithProposal.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {IOwnable} from \"../interfaces/IOwnable.sol\";\n\n/// @title The ConfirmedOwner contract\n/// @notice A contract with helpers for basic contract ownership.\ncontract ConfirmedOwnerWithProposal is IOwnable {\n  address private s_owner;\n  address private s_pendingOwner;\n\n  event OwnershipTransferRequested(address indexed from, address indexed to);\n  event OwnershipTransferred(address indexed from, address indexed to);\n\n  constructor(address newOwner, address pendingOwner) {\n    // solhint-disable-next-line custom-errors\n    require(newOwner != address(0), \"Cannot set owner to zero\");\n\n    s_owner = newOwner;\n    if (pendingOwner != address(0)) {\n      _transferOwnership(pendingOwner);\n    }\n  }\n\n  /// @notice Allows an owner to begin transferring ownership to a new address.\n  function transferOwnership(address to) public override onlyOwner {\n    _transferOwnership(to);\n  }\n\n  /// @notice Allows an ownership transfer to be completed by the recipient.\n  function acceptOwnership() external override {\n    // solhint-disable-next-line custom-errors\n    require(msg.sender == s_pendingOwner, \"Must be proposed owner\");\n\n    address oldOwner = s_owner;\n    s_owner = msg.sender;\n    s_pendingOwner = address(0);\n\n    emit OwnershipTransferred(oldOwner, msg.sender);\n  }\n\n  /// @notice Get the current owner\n  function owner() public view override returns (address) {\n    return s_owner;\n  }\n\n  /// @notice validate, transfer ownership, and emit relevant events\n  function _transferOwnership(address to) private {\n    // solhint-disable-next-line custom-errors\n    require(to != msg.sender, \"Cannot transfer to self\");\n\n    s_pendingOwner = to;\n\n    emit OwnershipTransferRequested(s_owner, to);\n  }\n\n  /// @notice validate access\n  function _validateOwnership() internal view {\n    // solhint-disable-next-line custom-errors\n    require(msg.sender == s_owner, \"Only callable by owner\");\n  }\n\n  /// @notice Reverts if called by anyone other than the contract owner.\n  modifier onlyOwner() {\n    _validateOwnership();\n    _;\n  }\n}\n"
      },
      "lib/ccip/contracts/src/v0.8/shared/interfaces/IOwnable.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ninterface IOwnable {\n  function owner() external returns (address);\n\n  function transferOwnership(address recipient) external;\n\n  function acceptOwnership() external;\n}\n"
      }
    },
    "settings": {
      "remappings": [
        "@openzeppelin/=lib/xERC20/lib/openzeppelin-contracts/",
        "ccip/=lib/ccip/contracts/",
        "ds-test/=lib/xERC20/lib/ds-test/src/",
        "erc4626-tests/=lib/xERC20/lib/openzeppelin-contracts/lib/erc4626-tests/",
        "forge-gas-snapshot/=lib/xERC20/lib/permit2/lib/forge-gas-snapshot/src/",
        "forge-std/=lib/forge-std/src/",
        "isolmate/=lib/xERC20/lib/isolmate/src/",
        "openzeppelin-contracts/=lib/xERC20/lib/openzeppelin-contracts/",
        "openzeppelin/=lib/xERC20/lib/openzeppelin-contracts/contracts/",
        "permit2/=lib/xERC20/lib/permit2/",
        "prb-test/=lib/xERC20/lib/prb-test/src/",
        "prb/test/=lib/xERC20/lib/prb-test/src/",
        "solmate/=lib/xERC20/lib/permit2/lib/solmate/",
        "xERC20/=lib/xERC20/"
      ],
      "optimizer": {
        "enabled": true,
        "runs": 200
      },
      "metadata": {
        "useLiteralContent": false,
        "bytecodeHash": "ipfs",
        "appendCBOR": true
      },
      "outputSelection": {
        "*": {
          "*": [
            "evm.bytecode",
            "evm.deployedBytecode",
            "devdoc",
            "userdoc",
            "metadata",
            "abi"
          ]
        }
      },
      "evmVersion": "paris",
      "viaIR": false,
      "libraries": {}
    }
  }}