services/cctp-relayer/contracts/mocktokenmessenger/mocktokenmessenger.contractinfo.json
{"solidity/MockTokenMessenger.sol:Address":{"code":"0x60566037600b82828239805160001a607314602a57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600080fdfea26469706673582212204751db3d3fcbfa211147ae7cf195b5d5a7cf565d7301c4706af60c8d8e93727f64736f6c63430008110033","runtime-code":"0x73000000000000000000000000000000000000000030146080604052600080fdfea26469706673582212204751db3d3fcbfa211147ae7cf195b5d5a7cf565d7301c4706af60c8d8e93727f64736f6c63430008110033","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity 0.8.17;\n\nabstract contract TokenMessengerEvents {\n /**\n * @notice Emitted when a DepositForBurn message is sent\n * @param nonce unique nonce reserved by message\n * @param burnToken address of token burnt on source domain\n * @param amount deposit amount\n * @param depositor address where deposit is transferred from\n * @param mintRecipient address receiving minted tokens on destination domain as bytes32\n * @param destinationDomain destination domain\n * @param destinationTokenMessenger address of TokenMessenger on destination domain as bytes32\n * @param destinationCaller authorized caller as bytes32 of receiveMessage() on destination domain, if not equal to bytes32(0).\n * If equal to bytes32(0), any address can call receiveMessage().\n */\n event DepositForBurn(\n uint64 indexed nonce,\n address indexed burnToken,\n uint256 amount,\n address indexed depositor,\n bytes32 mintRecipient,\n uint32 destinationDomain,\n bytes32 destinationTokenMessenger,\n bytes32 destinationCaller\n );\n\n /**\n * @notice Emitted when tokens are minted\n * @param mintRecipient recipient address of minted tokens\n * @param amount amount of minted tokens\n * @param mintToken contract address of minted token\n */\n event MintAndWithdraw(address indexed mintRecipient, uint256 amount, address indexed mintToken);\n}\n\ninterface IMessageTransmitter {\n /**\n * @notice Receives an incoming message, validating the header and passing\n * the body to application-specific handler.\n * @param message The message raw bytes\n * @param signature The message signature\n * @return success bool, true if successful\n */\n function receiveMessage(bytes calldata message, bytes calldata signature) external returns (bool success);\n\n /**\n * @notice Sends an outgoing message from the source domain, with a specified caller on the\n * destination domain.\n * @dev Increment nonce, format the message, and emit `MessageSent` event with message information.\n * WARNING: if the `destinationCaller` does not represent a valid address as bytes32, then it will not be possible\n * to broadcast the message on the destination domain. This is an advanced feature, and the standard\n * sendMessage() should be preferred for use cases where a specific destination caller is not required.\n * @param destinationDomain Domain of destination chain\n * @param recipient Address of message recipient on destination domain as bytes32\n * @param destinationCaller caller on the destination domain, as bytes32\n * @param messageBody Raw bytes content of message\n * @return nonce reserved by message\n */\n function sendMessageWithCaller(\n uint32 destinationDomain,\n bytes32 recipient,\n bytes32 destinationCaller,\n bytes calldata messageBody\n ) external returns (uint64);\n\n // ═══════════════════════════════════════════════════ VIEWS ═══════════════════════════════════════════════════════\n\n // Domain of chain on which the contract is deployed\n function localDomain() external view returns (uint32);\n\n // Next available nonce from this source domain\n function nextAvailableNonce() external view returns (uint64);\n}\n\ninterface ITokenMessenger {\n /**\n * @notice Deposits and burns tokens from sender to be minted on destination domain. The mint\n * on the destination domain must be called by `destinationCaller`.\n * WARNING: if the `destinationCaller` does not represent a valid address as bytes32, then it will not be possible\n * to broadcast the message on the destination domain. This is an advanced feature, and the standard\n * depositForBurn() should be preferred for use cases where a specific destination caller is not required.\n * Emits a `DepositForBurn` event.\n * @dev reverts if:\n * - given destinationCaller is zero address\n * - given burnToken is not supported\n * - given destinationDomain has no TokenMessenger registered\n * - transferFrom() reverts. For example, if sender's burnToken balance or approved allowance\n * to this contract is less than `amount`.\n * - burn() reverts. For example, if `amount` is 0.\n * - MessageTransmitter returns false or reverts.\n * @param amount amount of tokens to burn\n * @param destinationDomain destination domain\n * @param mintRecipient address of mint recipient on destination domain\n * @param burnToken address of contract to burn deposited tokens, on local domain\n * @param destinationCaller caller on the destination domain, as bytes32\n * @return nonce unique nonce reserved by message\n */\n function depositForBurnWithCaller(\n uint256 amount,\n uint32 destinationDomain,\n bytes32 mintRecipient,\n address burnToken,\n bytes32 destinationCaller\n ) external returns (uint64 nonce);\n\n /**\n * @notice Handles an incoming message received by the local MessageTransmitter,\n * and takes the appropriate action. For a burn message, mints the\n * associated token to the requested recipient on the local domain.\n * @dev Validates the local sender is the local MessageTransmitter, and the\n * remote sender is a registered remote TokenMessenger for `remoteDomain`.\n * @param remoteDomain The domain where the message originated from.\n * @param sender The sender of the message (remote TokenMessenger).\n * @param messageBody The message body bytes.\n * @return success Bool, true if successful.\n */\n function handleReceiveMessage(\n uint32 remoteDomain,\n bytes32 sender,\n bytes calldata messageBody\n ) external returns (bool success);\n\n // ═══════════════════════════════════════════════════ VIEWS ═══════════════════════════════════════════════════════\n\n // Local Message Transmitter responsible for sending and receiving messages to/from remote domains\n function localMessageTransmitter() external view returns (address);\n\n // Minter responsible for minting and burning tokens on the local domain\n function localMinter() external view returns (address);\n}\n\ninterface ITokenMinter {\n /**\n * @notice Mints `amount` of local tokens corresponding to the\n * given (`sourceDomain`, `burnToken`) pair, to `to` address.\n * @dev reverts if the (`sourceDomain`, `burnToken`) pair does not\n * map to a nonzero local token address. This mapping can be queried using\n * getLocalToken().\n * @param sourceDomain Source domain where `burnToken` was burned.\n * @param burnToken Burned token address as bytes32.\n * @param to Address to receive minted tokens, corresponding to `burnToken`,\n * on this domain.\n * @param amount Amount of tokens to mint. Must be less than or equal\n * to the minterAllowance of this TokenMinter for given `_mintToken`.\n * @return mintToken token minted.\n */\n function mint(\n uint32 sourceDomain,\n bytes32 burnToken,\n address to,\n uint256 amount\n ) external returns (address mintToken);\n\n /**\n * @notice Burn tokens owned by this ITokenMinter.\n * @param burnToken burnable token.\n * @param amount amount of tokens to burn. Must be less than or equal to this ITokenMinter's\n * account balance of the given `_burnToken`.\n */\n function burn(address burnToken, uint256 amount) external;\n\n /**\n * @notice Get the local token associated with the given remote domain and token.\n * @param remoteDomain Remote domain\n * @param remoteToken Remote token\n * @return local token address\n */\n function getLocalToken(uint32 remoteDomain, bytes32 remoteToken) external view returns (address);\n\n // local token (address) =\u003e maximum burn amounts per message\n function burnLimitsPerMessage(address token) external view returns (uint256);\n}\n\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/utils/SafeERC20.sol)\n\n// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\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(\n address from,\n address to,\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\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\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 * [IMPORTANT]\n * ====\n * You shouldn't rely on `isContract` to protect against flash loan attacks!\n *\n * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\n * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\n * constructor.\n * ====\n */\n function isContract(address account) internal view returns (bool) {\n // This method relies on extcodesize/address.code.length, which returns 0\n // for contracts in construction, since the code is only stored at the end\n // of the constructor execution.\n\n return account.code.length \u003e 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 \u003e= amount, \"Address: insufficient balance\");\n\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(\n address target,\n bytes memory data,\n string memory errorMessage\n ) 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(\n address target,\n bytes memory data,\n uint256 value\n ) 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(\n address target,\n bytes memory data,\n uint256 value,\n string memory errorMessage\n ) internal returns (bytes memory) {\n require(address(this).balance \u003e= value, \"Address: insufficient balance for call\");\n require(isContract(target), \"Address: call to non-contract\");\n\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(\n address target,\n bytes memory data,\n string memory errorMessage\n ) internal view returns (bytes memory) {\n require(isContract(target), \"Address: static call to non-contract\");\n\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResult(success, returndata, errorMessage);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n *\n * _Available since v3.4._\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionDelegateCall(target, data, \"Address: low-level delegate call failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n * but performing a delegate call.\n *\n * _Available since v3.4._\n */\n function functionDelegateCall(\n address target,\n bytes memory data,\n string memory errorMessage\n ) internal returns (bytes memory) {\n require(isContract(target), \"Address: delegate call to non-contract\");\n\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResult(success, returndata, errorMessage);\n }\n\n /**\n * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\n * revert reason using the provided one.\n *\n * _Available since v4.3._\n */\n function verifyCallResult(\n bool success,\n bytes memory returndata,\n string memory errorMessage\n ) internal 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 \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n\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\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n function safeTransfer(\n IERC20 token,\n address to,\n uint256 value\n ) internal {\n _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\n }\n\n function safeTransferFrom(\n IERC20 token,\n address from,\n address to,\n uint256 value\n ) internal {\n _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));\n }\n\n /**\n * @dev Deprecated. This function has issues similar to the ones found in\n * {IERC20-approve}, and its usage is discouraged.\n *\n * Whenever possible, use {safeIncreaseAllowance} and\n * {safeDecreaseAllowance} instead.\n */\n function safeApprove(\n IERC20 token,\n address spender,\n uint256 value\n ) internal {\n // safeApprove should only be called when setting an initial allowance,\n // or when resetting it to zero. To increase and decrease it, use\n // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\n require(\n (value == 0) || (token.allowance(address(this), spender) == 0),\n \"SafeERC20: approve from non-zero to non-zero allowance\"\n );\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\n }\n\n function safeIncreaseAllowance(\n IERC20 token,\n address spender,\n uint256 value\n ) internal {\n uint256 newAllowance = token.allowance(address(this), spender) + value;\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\n }\n\n function safeDecreaseAllowance(\n IERC20 token,\n address spender,\n uint256 value\n ) internal {\n unchecked {\n uint256 oldAllowance = token.allowance(address(this), spender);\n require(oldAllowance \u003e= value, \"SafeERC20: decreased allowance below zero\");\n uint256 newAllowance = oldAllowance - value;\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data, \"SafeERC20: low-level call failed\");\n if (returndata.length \u003e 0) {\n // Return data is optional\n require(abi.decode(returndata, (bool)), \"SafeERC20: ERC20 operation did not succeed\");\n }\n }\n}\n\ncontract MockTokenMessenger is TokenMessengerEvents, ITokenMessenger {\n using SafeERC20 for IERC20;\n\n address public override localMessageTransmitter;\n address public override localMinter;\n mapping(uint32 =\u003e bytes32) public remoteTokenMessenger;\n\n constructor(address localMessageTransmitter_) {\n localMessageTransmitter = localMessageTransmitter_;\n }\n\n function setLocalMinter(address localMinter_) external {\n localMinter = localMinter_;\n }\n\n function setRemoteTokenMessenger(uint32 remoteDomain, bytes32 remoteTokenMessenger_) external {\n remoteTokenMessenger[remoteDomain] = remoteTokenMessenger_;\n }\n\n function depositForBurnWithCaller(\n uint256 amount,\n uint32 destinationDomain,\n bytes32 mintRecipient,\n address burnToken,\n bytes32 destinationCaller\n ) external returns (uint64 nonce) {\n IERC20(burnToken).safeTransferFrom(msg.sender, localMinter, amount);\n ITokenMinter(localMinter).burn(burnToken, amount);\n bytes memory messageBody = formatTokenMessage(amount, mintRecipient, burnToken);\n nonce = IMessageTransmitter(localMessageTransmitter).sendMessageWithCaller(\n destinationDomain,\n remoteTokenMessenger[destinationDomain],\n destinationCaller,\n messageBody\n );\n emit DepositForBurn({\n nonce: nonce,\n burnToken: burnToken,\n amount: amount,\n depositor: msg.sender,\n mintRecipient: mintRecipient,\n destinationDomain: destinationDomain,\n destinationTokenMessenger: remoteTokenMessenger[destinationDomain],\n destinationCaller: destinationCaller\n });\n }\n\n function handleReceiveMessage(\n uint32 remoteDomain,\n bytes32 sender,\n bytes calldata messageBody\n ) external returns (bool success) {\n require(msg.sender == localMessageTransmitter, \"Invalid message transmitter\");\n require(sender == remoteTokenMessenger[remoteDomain], \"Remote TokenMessenger unsupported\");\n (uint256 amount, bytes32 mintRecipient, bytes32 burnToken) = abi.decode(\n messageBody,\n (uint256, bytes32, bytes32)\n );\n address mintToken = ITokenMinter(localMinter).mint(\n remoteDomain,\n burnToken,\n address(uint160(uint256(mintRecipient))),\n amount\n );\n emit MintAndWithdraw({\n mintRecipient: address(uint160(uint256(mintRecipient))),\n amount: amount,\n mintToken: mintToken\n });\n return true;\n }\n\n function formatTokenMessage(\n uint256 amount,\n bytes32 mintRecipient,\n address burnToken\n ) public pure returns (bytes memory tokenMessage) {\n return abi.encode(amount, mintRecipient, bytes32(uint256(uint160(burnToken))));\n }\n}\n","language":"Solidity","languageVersion":"0.8.17","compilerVersion":"0.8.17","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../","srcMap":"11304:8061:0:-:0;;;;;;;;;;;;;;;-1:-1:-1;;;11304:8061:0;;;;;;;;;;;;;;;;;","srcMapRuntime":"11304:8061:0:-:0;;;;;;;;","abiDefinition":[],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"details":"Collection of functions related to the address type","kind":"dev","methods":{},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.17+commit.8df45f5f\"},\"language\":\"Solidity\",\"output\":{\"abi\":[],\"devdoc\":{\"details\":\"Collection of functions related to the address type\",\"kind\":\"dev\",\"methods\":{},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/MockTokenMessenger.sol\":\"Address\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/MockTokenMessenger.sol\":{\"keccak256\":\"0x676112f99e502493a5f5dddf4043b92d8baf8accb1bdc704a0e77529ddba46d6\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://b7f4c1c133460718570f7c97bf1f098cc47625b54e419be0bc87dcbc1863e3ce\",\"dweb:/ipfs/QmdAEfnnzhMPUcAaAGnG9zeY8KPpnLrR9PKx4VMSqb6Usx\"]}},\"version\":1}"},"hashes":{}},"solidity/MockTokenMessenger.sol:IERC20":{"code":"0x","runtime-code":"0x","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity 0.8.17;\n\nabstract contract TokenMessengerEvents {\n /**\n * @notice Emitted when a DepositForBurn message is sent\n * @param nonce unique nonce reserved by message\n * @param burnToken address of token burnt on source domain\n * @param amount deposit amount\n * @param depositor address where deposit is transferred from\n * @param mintRecipient address receiving minted tokens on destination domain as bytes32\n * @param destinationDomain destination domain\n * @param destinationTokenMessenger address of TokenMessenger on destination domain as bytes32\n * @param destinationCaller authorized caller as bytes32 of receiveMessage() on destination domain, if not equal to bytes32(0).\n * If equal to bytes32(0), any address can call receiveMessage().\n */\n event DepositForBurn(\n uint64 indexed nonce,\n address indexed burnToken,\n uint256 amount,\n address indexed depositor,\n bytes32 mintRecipient,\n uint32 destinationDomain,\n bytes32 destinationTokenMessenger,\n bytes32 destinationCaller\n );\n\n /**\n * @notice Emitted when tokens are minted\n * @param mintRecipient recipient address of minted tokens\n * @param amount amount of minted tokens\n * @param mintToken contract address of minted token\n */\n event MintAndWithdraw(address indexed mintRecipient, uint256 amount, address indexed mintToken);\n}\n\ninterface IMessageTransmitter {\n /**\n * @notice Receives an incoming message, validating the header and passing\n * the body to application-specific handler.\n * @param message The message raw bytes\n * @param signature The message signature\n * @return success bool, true if successful\n */\n function receiveMessage(bytes calldata message, bytes calldata signature) external returns (bool success);\n\n /**\n * @notice Sends an outgoing message from the source domain, with a specified caller on the\n * destination domain.\n * @dev Increment nonce, format the message, and emit `MessageSent` event with message information.\n * WARNING: if the `destinationCaller` does not represent a valid address as bytes32, then it will not be possible\n * to broadcast the message on the destination domain. This is an advanced feature, and the standard\n * sendMessage() should be preferred for use cases where a specific destination caller is not required.\n * @param destinationDomain Domain of destination chain\n * @param recipient Address of message recipient on destination domain as bytes32\n * @param destinationCaller caller on the destination domain, as bytes32\n * @param messageBody Raw bytes content of message\n * @return nonce reserved by message\n */\n function sendMessageWithCaller(\n uint32 destinationDomain,\n bytes32 recipient,\n bytes32 destinationCaller,\n bytes calldata messageBody\n ) external returns (uint64);\n\n // ═══════════════════════════════════════════════════ VIEWS ═══════════════════════════════════════════════════════\n\n // Domain of chain on which the contract is deployed\n function localDomain() external view returns (uint32);\n\n // Next available nonce from this source domain\n function nextAvailableNonce() external view returns (uint64);\n}\n\ninterface ITokenMessenger {\n /**\n * @notice Deposits and burns tokens from sender to be minted on destination domain. The mint\n * on the destination domain must be called by `destinationCaller`.\n * WARNING: if the `destinationCaller` does not represent a valid address as bytes32, then it will not be possible\n * to broadcast the message on the destination domain. This is an advanced feature, and the standard\n * depositForBurn() should be preferred for use cases where a specific destination caller is not required.\n * Emits a `DepositForBurn` event.\n * @dev reverts if:\n * - given destinationCaller is zero address\n * - given burnToken is not supported\n * - given destinationDomain has no TokenMessenger registered\n * - transferFrom() reverts. For example, if sender's burnToken balance or approved allowance\n * to this contract is less than `amount`.\n * - burn() reverts. For example, if `amount` is 0.\n * - MessageTransmitter returns false or reverts.\n * @param amount amount of tokens to burn\n * @param destinationDomain destination domain\n * @param mintRecipient address of mint recipient on destination domain\n * @param burnToken address of contract to burn deposited tokens, on local domain\n * @param destinationCaller caller on the destination domain, as bytes32\n * @return nonce unique nonce reserved by message\n */\n function depositForBurnWithCaller(\n uint256 amount,\n uint32 destinationDomain,\n bytes32 mintRecipient,\n address burnToken,\n bytes32 destinationCaller\n ) external returns (uint64 nonce);\n\n /**\n * @notice Handles an incoming message received by the local MessageTransmitter,\n * and takes the appropriate action. For a burn message, mints the\n * associated token to the requested recipient on the local domain.\n * @dev Validates the local sender is the local MessageTransmitter, and the\n * remote sender is a registered remote TokenMessenger for `remoteDomain`.\n * @param remoteDomain The domain where the message originated from.\n * @param sender The sender of the message (remote TokenMessenger).\n * @param messageBody The message body bytes.\n * @return success Bool, true if successful.\n */\n function handleReceiveMessage(\n uint32 remoteDomain,\n bytes32 sender,\n bytes calldata messageBody\n ) external returns (bool success);\n\n // ═══════════════════════════════════════════════════ VIEWS ═══════════════════════════════════════════════════════\n\n // Local Message Transmitter responsible for sending and receiving messages to/from remote domains\n function localMessageTransmitter() external view returns (address);\n\n // Minter responsible for minting and burning tokens on the local domain\n function localMinter() external view returns (address);\n}\n\ninterface ITokenMinter {\n /**\n * @notice Mints `amount` of local tokens corresponding to the\n * given (`sourceDomain`, `burnToken`) pair, to `to` address.\n * @dev reverts if the (`sourceDomain`, `burnToken`) pair does not\n * map to a nonzero local token address. This mapping can be queried using\n * getLocalToken().\n * @param sourceDomain Source domain where `burnToken` was burned.\n * @param burnToken Burned token address as bytes32.\n * @param to Address to receive minted tokens, corresponding to `burnToken`,\n * on this domain.\n * @param amount Amount of tokens to mint. Must be less than or equal\n * to the minterAllowance of this TokenMinter for given `_mintToken`.\n * @return mintToken token minted.\n */\n function mint(\n uint32 sourceDomain,\n bytes32 burnToken,\n address to,\n uint256 amount\n ) external returns (address mintToken);\n\n /**\n * @notice Burn tokens owned by this ITokenMinter.\n * @param burnToken burnable token.\n * @param amount amount of tokens to burn. Must be less than or equal to this ITokenMinter's\n * account balance of the given `_burnToken`.\n */\n function burn(address burnToken, uint256 amount) external;\n\n /**\n * @notice Get the local token associated with the given remote domain and token.\n * @param remoteDomain Remote domain\n * @param remoteToken Remote token\n * @return local token address\n */\n function getLocalToken(uint32 remoteDomain, bytes32 remoteToken) external view returns (address);\n\n // local token (address) =\u003e maximum burn amounts per message\n function burnLimitsPerMessage(address token) external view returns (uint256);\n}\n\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/utils/SafeERC20.sol)\n\n// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\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(\n address from,\n address to,\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\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\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 * [IMPORTANT]\n * ====\n * You shouldn't rely on `isContract` to protect against flash loan attacks!\n *\n * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\n * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\n * constructor.\n * ====\n */\n function isContract(address account) internal view returns (bool) {\n // This method relies on extcodesize/address.code.length, which returns 0\n // for contracts in construction, since the code is only stored at the end\n // of the constructor execution.\n\n return account.code.length \u003e 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 \u003e= amount, \"Address: insufficient balance\");\n\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(\n address target,\n bytes memory data,\n string memory errorMessage\n ) 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(\n address target,\n bytes memory data,\n uint256 value\n ) 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(\n address target,\n bytes memory data,\n uint256 value,\n string memory errorMessage\n ) internal returns (bytes memory) {\n require(address(this).balance \u003e= value, \"Address: insufficient balance for call\");\n require(isContract(target), \"Address: call to non-contract\");\n\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(\n address target,\n bytes memory data,\n string memory errorMessage\n ) internal view returns (bytes memory) {\n require(isContract(target), \"Address: static call to non-contract\");\n\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResult(success, returndata, errorMessage);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n *\n * _Available since v3.4._\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionDelegateCall(target, data, \"Address: low-level delegate call failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n * but performing a delegate call.\n *\n * _Available since v3.4._\n */\n function functionDelegateCall(\n address target,\n bytes memory data,\n string memory errorMessage\n ) internal returns (bytes memory) {\n require(isContract(target), \"Address: delegate call to non-contract\");\n\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResult(success, returndata, errorMessage);\n }\n\n /**\n * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\n * revert reason using the provided one.\n *\n * _Available since v4.3._\n */\n function verifyCallResult(\n bool success,\n bytes memory returndata,\n string memory errorMessage\n ) internal 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 \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n\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\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n function safeTransfer(\n IERC20 token,\n address to,\n uint256 value\n ) internal {\n _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\n }\n\n function safeTransferFrom(\n IERC20 token,\n address from,\n address to,\n uint256 value\n ) internal {\n _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));\n }\n\n /**\n * @dev Deprecated. This function has issues similar to the ones found in\n * {IERC20-approve}, and its usage is discouraged.\n *\n * Whenever possible, use {safeIncreaseAllowance} and\n * {safeDecreaseAllowance} instead.\n */\n function safeApprove(\n IERC20 token,\n address spender,\n uint256 value\n ) internal {\n // safeApprove should only be called when setting an initial allowance,\n // or when resetting it to zero. To increase and decrease it, use\n // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\n require(\n (value == 0) || (token.allowance(address(this), spender) == 0),\n \"SafeERC20: approve from non-zero to non-zero allowance\"\n );\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\n }\n\n function safeIncreaseAllowance(\n IERC20 token,\n address spender,\n uint256 value\n ) internal {\n uint256 newAllowance = token.allowance(address(this), spender) + value;\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\n }\n\n function safeDecreaseAllowance(\n IERC20 token,\n address spender,\n uint256 value\n ) internal {\n unchecked {\n uint256 oldAllowance = token.allowance(address(this), spender);\n require(oldAllowance \u003e= value, \"SafeERC20: decreased allowance below zero\");\n uint256 newAllowance = oldAllowance - value;\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data, \"SafeERC20: low-level call failed\");\n if (returndata.length \u003e 0) {\n // Return data is optional\n require(abi.decode(returndata, (bool)), \"SafeERC20: ERC20 operation did not succeed\");\n }\n }\n}\n\ncontract MockTokenMessenger is TokenMessengerEvents, ITokenMessenger {\n using SafeERC20 for IERC20;\n\n address public override localMessageTransmitter;\n address public override localMinter;\n mapping(uint32 =\u003e bytes32) public remoteTokenMessenger;\n\n constructor(address localMessageTransmitter_) {\n localMessageTransmitter = localMessageTransmitter_;\n }\n\n function setLocalMinter(address localMinter_) external {\n localMinter = localMinter_;\n }\n\n function setRemoteTokenMessenger(uint32 remoteDomain, bytes32 remoteTokenMessenger_) external {\n remoteTokenMessenger[remoteDomain] = remoteTokenMessenger_;\n }\n\n function depositForBurnWithCaller(\n uint256 amount,\n uint32 destinationDomain,\n bytes32 mintRecipient,\n address burnToken,\n bytes32 destinationCaller\n ) external returns (uint64 nonce) {\n IERC20(burnToken).safeTransferFrom(msg.sender, localMinter, amount);\n ITokenMinter(localMinter).burn(burnToken, amount);\n bytes memory messageBody = formatTokenMessage(amount, mintRecipient, burnToken);\n nonce = IMessageTransmitter(localMessageTransmitter).sendMessageWithCaller(\n destinationDomain,\n remoteTokenMessenger[destinationDomain],\n destinationCaller,\n messageBody\n );\n emit DepositForBurn({\n nonce: nonce,\n burnToken: burnToken,\n amount: amount,\n depositor: msg.sender,\n mintRecipient: mintRecipient,\n destinationDomain: destinationDomain,\n destinationTokenMessenger: remoteTokenMessenger[destinationDomain],\n destinationCaller: destinationCaller\n });\n }\n\n function handleReceiveMessage(\n uint32 remoteDomain,\n bytes32 sender,\n bytes calldata messageBody\n ) external returns (bool success) {\n require(msg.sender == localMessageTransmitter, \"Invalid message transmitter\");\n require(sender == remoteTokenMessenger[remoteDomain], \"Remote TokenMessenger unsupported\");\n (uint256 amount, bytes32 mintRecipient, bytes32 burnToken) = abi.decode(\n messageBody,\n (uint256, bytes32, bytes32)\n );\n address mintToken = ITokenMinter(localMinter).mint(\n remoteDomain,\n burnToken,\n address(uint160(uint256(mintRecipient))),\n amount\n );\n emit MintAndWithdraw({\n mintRecipient: address(uint160(uint256(mintRecipient))),\n amount: amount,\n mintToken: mintToken\n });\n return true;\n }\n\n function formatTokenMessage(\n uint256 amount,\n bytes32 mintRecipient,\n address burnToken\n ) public pure returns (bytes memory tokenMessage) {\n return abi.encode(amount, mintRecipient, bytes32(uint256(uint160(burnToken))));\n }\n}\n","language":"Solidity","languageVersion":"0.8.17","compilerVersion":"0.8.17","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../","srcMap":"","srcMapRuntime":"","abiDefinition":[{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Transfer","type":"event"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"}],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"details":"Interface of the ERC20 standard as defined in the EIP.","events":{"Approval(address,address,uint256)":{"details":"Emitted when the allowance of a `spender` for an `owner` is set by a call to {approve}. `value` is the new allowance."},"Transfer(address,address,uint256)":{"details":"Emitted when `value` tokens are moved from one account (`from`) to another (`to`). Note that `value` may be zero."}},"kind":"dev","methods":{"allowance(address,address)":{"details":"Returns the remaining number of tokens that `spender` will be allowed to spend on behalf of `owner` through {transferFrom}. This is zero by default. This value changes when {approve} or {transferFrom} are called."},"approve(address,uint256)":{"details":"Sets `amount` as the allowance of `spender` over the caller's tokens. Returns a boolean value indicating whether the operation succeeded. IMPORTANT: Beware that changing an allowance with this method brings the risk that someone may use both the old and the new allowance by unfortunate transaction ordering. One possible solution to mitigate this race condition is to first reduce the spender's allowance to 0 and set the desired value afterwards: https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 Emits an {Approval} event."},"balanceOf(address)":{"details":"Returns the amount of tokens owned by `account`."},"totalSupply()":{"details":"Returns the amount of tokens in existence."},"transfer(address,uint256)":{"details":"Moves `amount` tokens from the caller's account to `to`. Returns a boolean value indicating whether the operation succeeded. Emits a {Transfer} event."},"transferFrom(address,address,uint256)":{"details":"Moves `amount` tokens from `from` to `to` using the allowance mechanism. `amount` is then deducted from the caller's allowance. Returns a boolean value indicating whether the operation succeeded. Emits a {Transfer} event."}},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.17+commit.8df45f5f\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"Approval\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"Transfer\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"}],\"name\":\"allowance\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"approve\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"balanceOf\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"totalSupply\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"transfer\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"transferFrom\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"Interface of the ERC20 standard as defined in the EIP.\",\"events\":{\"Approval(address,address,uint256)\":{\"details\":\"Emitted when the allowance of a `spender` for an `owner` is set by a call to {approve}. `value` is the new allowance.\"},\"Transfer(address,address,uint256)\":{\"details\":\"Emitted when `value` tokens are moved from one account (`from`) to another (`to`). Note that `value` may be zero.\"}},\"kind\":\"dev\",\"methods\":{\"allowance(address,address)\":{\"details\":\"Returns the remaining number of tokens that `spender` will be allowed to spend on behalf of `owner` through {transferFrom}. This is zero by default. This value changes when {approve} or {transferFrom} are called.\"},\"approve(address,uint256)\":{\"details\":\"Sets `amount` as the allowance of `spender` over the caller's tokens. Returns a boolean value indicating whether the operation succeeded. IMPORTANT: Beware that changing an allowance with this method brings the risk that someone may use both the old and the new allowance by unfortunate transaction ordering. One possible solution to mitigate this race condition is to first reduce the spender's allowance to 0 and set the desired value afterwards: https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 Emits an {Approval} event.\"},\"balanceOf(address)\":{\"details\":\"Returns the amount of tokens owned by `account`.\"},\"totalSupply()\":{\"details\":\"Returns the amount of tokens in existence.\"},\"transfer(address,uint256)\":{\"details\":\"Moves `amount` tokens from the caller's account to `to`. Returns a boolean value indicating whether the operation succeeded. Emits a {Transfer} event.\"},\"transferFrom(address,address,uint256)\":{\"details\":\"Moves `amount` tokens from `from` to `to` using the allowance mechanism. `amount` is then deducted from the caller's allowance. Returns a boolean value indicating whether the operation succeeded. Emits a {Transfer} event.\"}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/MockTokenMessenger.sol\":\"IERC20\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/MockTokenMessenger.sol\":{\"keccak256\":\"0x676112f99e502493a5f5dddf4043b92d8baf8accb1bdc704a0e77529ddba46d6\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://b7f4c1c133460718570f7c97bf1f098cc47625b54e419be0bc87dcbc1863e3ce\",\"dweb:/ipfs/QmdAEfnnzhMPUcAaAGnG9zeY8KPpnLrR9PKx4VMSqb6Usx\"]}},\"version\":1}"},"hashes":{"allowance(address,address)":"dd62ed3e","approve(address,uint256)":"095ea7b3","balanceOf(address)":"70a08231","totalSupply()":"18160ddd","transfer(address,uint256)":"a9059cbb","transferFrom(address,address,uint256)":"23b872dd"}},"solidity/MockTokenMessenger.sol:IMessageTransmitter":{"code":"0x","runtime-code":"0x","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity 0.8.17;\n\nabstract contract TokenMessengerEvents {\n /**\n * @notice Emitted when a DepositForBurn message is sent\n * @param nonce unique nonce reserved by message\n * @param burnToken address of token burnt on source domain\n * @param amount deposit amount\n * @param depositor address where deposit is transferred from\n * @param mintRecipient address receiving minted tokens on destination domain as bytes32\n * @param destinationDomain destination domain\n * @param destinationTokenMessenger address of TokenMessenger on destination domain as bytes32\n * @param destinationCaller authorized caller as bytes32 of receiveMessage() on destination domain, if not equal to bytes32(0).\n * If equal to bytes32(0), any address can call receiveMessage().\n */\n event DepositForBurn(\n uint64 indexed nonce,\n address indexed burnToken,\n uint256 amount,\n address indexed depositor,\n bytes32 mintRecipient,\n uint32 destinationDomain,\n bytes32 destinationTokenMessenger,\n bytes32 destinationCaller\n );\n\n /**\n * @notice Emitted when tokens are minted\n * @param mintRecipient recipient address of minted tokens\n * @param amount amount of minted tokens\n * @param mintToken contract address of minted token\n */\n event MintAndWithdraw(address indexed mintRecipient, uint256 amount, address indexed mintToken);\n}\n\ninterface IMessageTransmitter {\n /**\n * @notice Receives an incoming message, validating the header and passing\n * the body to application-specific handler.\n * @param message The message raw bytes\n * @param signature The message signature\n * @return success bool, true if successful\n */\n function receiveMessage(bytes calldata message, bytes calldata signature) external returns (bool success);\n\n /**\n * @notice Sends an outgoing message from the source domain, with a specified caller on the\n * destination domain.\n * @dev Increment nonce, format the message, and emit `MessageSent` event with message information.\n * WARNING: if the `destinationCaller` does not represent a valid address as bytes32, then it will not be possible\n * to broadcast the message on the destination domain. This is an advanced feature, and the standard\n * sendMessage() should be preferred for use cases where a specific destination caller is not required.\n * @param destinationDomain Domain of destination chain\n * @param recipient Address of message recipient on destination domain as bytes32\n * @param destinationCaller caller on the destination domain, as bytes32\n * @param messageBody Raw bytes content of message\n * @return nonce reserved by message\n */\n function sendMessageWithCaller(\n uint32 destinationDomain,\n bytes32 recipient,\n bytes32 destinationCaller,\n bytes calldata messageBody\n ) external returns (uint64);\n\n // ═══════════════════════════════════════════════════ VIEWS ═══════════════════════════════════════════════════════\n\n // Domain of chain on which the contract is deployed\n function localDomain() external view returns (uint32);\n\n // Next available nonce from this source domain\n function nextAvailableNonce() external view returns (uint64);\n}\n\ninterface ITokenMessenger {\n /**\n * @notice Deposits and burns tokens from sender to be minted on destination domain. The mint\n * on the destination domain must be called by `destinationCaller`.\n * WARNING: if the `destinationCaller` does not represent a valid address as bytes32, then it will not be possible\n * to broadcast the message on the destination domain. This is an advanced feature, and the standard\n * depositForBurn() should be preferred for use cases where a specific destination caller is not required.\n * Emits a `DepositForBurn` event.\n * @dev reverts if:\n * - given destinationCaller is zero address\n * - given burnToken is not supported\n * - given destinationDomain has no TokenMessenger registered\n * - transferFrom() reverts. For example, if sender's burnToken balance or approved allowance\n * to this contract is less than `amount`.\n * - burn() reverts. For example, if `amount` is 0.\n * - MessageTransmitter returns false or reverts.\n * @param amount amount of tokens to burn\n * @param destinationDomain destination domain\n * @param mintRecipient address of mint recipient on destination domain\n * @param burnToken address of contract to burn deposited tokens, on local domain\n * @param destinationCaller caller on the destination domain, as bytes32\n * @return nonce unique nonce reserved by message\n */\n function depositForBurnWithCaller(\n uint256 amount,\n uint32 destinationDomain,\n bytes32 mintRecipient,\n address burnToken,\n bytes32 destinationCaller\n ) external returns (uint64 nonce);\n\n /**\n * @notice Handles an incoming message received by the local MessageTransmitter,\n * and takes the appropriate action. For a burn message, mints the\n * associated token to the requested recipient on the local domain.\n * @dev Validates the local sender is the local MessageTransmitter, and the\n * remote sender is a registered remote TokenMessenger for `remoteDomain`.\n * @param remoteDomain The domain where the message originated from.\n * @param sender The sender of the message (remote TokenMessenger).\n * @param messageBody The message body bytes.\n * @return success Bool, true if successful.\n */\n function handleReceiveMessage(\n uint32 remoteDomain,\n bytes32 sender,\n bytes calldata messageBody\n ) external returns (bool success);\n\n // ═══════════════════════════════════════════════════ VIEWS ═══════════════════════════════════════════════════════\n\n // Local Message Transmitter responsible for sending and receiving messages to/from remote domains\n function localMessageTransmitter() external view returns (address);\n\n // Minter responsible for minting and burning tokens on the local domain\n function localMinter() external view returns (address);\n}\n\ninterface ITokenMinter {\n /**\n * @notice Mints `amount` of local tokens corresponding to the\n * given (`sourceDomain`, `burnToken`) pair, to `to` address.\n * @dev reverts if the (`sourceDomain`, `burnToken`) pair does not\n * map to a nonzero local token address. This mapping can be queried using\n * getLocalToken().\n * @param sourceDomain Source domain where `burnToken` was burned.\n * @param burnToken Burned token address as bytes32.\n * @param to Address to receive minted tokens, corresponding to `burnToken`,\n * on this domain.\n * @param amount Amount of tokens to mint. Must be less than or equal\n * to the minterAllowance of this TokenMinter for given `_mintToken`.\n * @return mintToken token minted.\n */\n function mint(\n uint32 sourceDomain,\n bytes32 burnToken,\n address to,\n uint256 amount\n ) external returns (address mintToken);\n\n /**\n * @notice Burn tokens owned by this ITokenMinter.\n * @param burnToken burnable token.\n * @param amount amount of tokens to burn. Must be less than or equal to this ITokenMinter's\n * account balance of the given `_burnToken`.\n */\n function burn(address burnToken, uint256 amount) external;\n\n /**\n * @notice Get the local token associated with the given remote domain and token.\n * @param remoteDomain Remote domain\n * @param remoteToken Remote token\n * @return local token address\n */\n function getLocalToken(uint32 remoteDomain, bytes32 remoteToken) external view returns (address);\n\n // local token (address) =\u003e maximum burn amounts per message\n function burnLimitsPerMessage(address token) external view returns (uint256);\n}\n\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/utils/SafeERC20.sol)\n\n// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\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(\n address from,\n address to,\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\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\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 * [IMPORTANT]\n * ====\n * You shouldn't rely on `isContract` to protect against flash loan attacks!\n *\n * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\n * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\n * constructor.\n * ====\n */\n function isContract(address account) internal view returns (bool) {\n // This method relies on extcodesize/address.code.length, which returns 0\n // for contracts in construction, since the code is only stored at the end\n // of the constructor execution.\n\n return account.code.length \u003e 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 \u003e= amount, \"Address: insufficient balance\");\n\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(\n address target,\n bytes memory data,\n string memory errorMessage\n ) 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(\n address target,\n bytes memory data,\n uint256 value\n ) 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(\n address target,\n bytes memory data,\n uint256 value,\n string memory errorMessage\n ) internal returns (bytes memory) {\n require(address(this).balance \u003e= value, \"Address: insufficient balance for call\");\n require(isContract(target), \"Address: call to non-contract\");\n\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(\n address target,\n bytes memory data,\n string memory errorMessage\n ) internal view returns (bytes memory) {\n require(isContract(target), \"Address: static call to non-contract\");\n\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResult(success, returndata, errorMessage);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n *\n * _Available since v3.4._\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionDelegateCall(target, data, \"Address: low-level delegate call failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n * but performing a delegate call.\n *\n * _Available since v3.4._\n */\n function functionDelegateCall(\n address target,\n bytes memory data,\n string memory errorMessage\n ) internal returns (bytes memory) {\n require(isContract(target), \"Address: delegate call to non-contract\");\n\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResult(success, returndata, errorMessage);\n }\n\n /**\n * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\n * revert reason using the provided one.\n *\n * _Available since v4.3._\n */\n function verifyCallResult(\n bool success,\n bytes memory returndata,\n string memory errorMessage\n ) internal 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 \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n\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\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n function safeTransfer(\n IERC20 token,\n address to,\n uint256 value\n ) internal {\n _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\n }\n\n function safeTransferFrom(\n IERC20 token,\n address from,\n address to,\n uint256 value\n ) internal {\n _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));\n }\n\n /**\n * @dev Deprecated. This function has issues similar to the ones found in\n * {IERC20-approve}, and its usage is discouraged.\n *\n * Whenever possible, use {safeIncreaseAllowance} and\n * {safeDecreaseAllowance} instead.\n */\n function safeApprove(\n IERC20 token,\n address spender,\n uint256 value\n ) internal {\n // safeApprove should only be called when setting an initial allowance,\n // or when resetting it to zero. To increase and decrease it, use\n // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\n require(\n (value == 0) || (token.allowance(address(this), spender) == 0),\n \"SafeERC20: approve from non-zero to non-zero allowance\"\n );\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\n }\n\n function safeIncreaseAllowance(\n IERC20 token,\n address spender,\n uint256 value\n ) internal {\n uint256 newAllowance = token.allowance(address(this), spender) + value;\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\n }\n\n function safeDecreaseAllowance(\n IERC20 token,\n address spender,\n uint256 value\n ) internal {\n unchecked {\n uint256 oldAllowance = token.allowance(address(this), spender);\n require(oldAllowance \u003e= value, \"SafeERC20: decreased allowance below zero\");\n uint256 newAllowance = oldAllowance - value;\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data, \"SafeERC20: low-level call failed\");\n if (returndata.length \u003e 0) {\n // Return data is optional\n require(abi.decode(returndata, (bool)), \"SafeERC20: ERC20 operation did not succeed\");\n }\n }\n}\n\ncontract MockTokenMessenger is TokenMessengerEvents, ITokenMessenger {\n using SafeERC20 for IERC20;\n\n address public override localMessageTransmitter;\n address public override localMinter;\n mapping(uint32 =\u003e bytes32) public remoteTokenMessenger;\n\n constructor(address localMessageTransmitter_) {\n localMessageTransmitter = localMessageTransmitter_;\n }\n\n function setLocalMinter(address localMinter_) external {\n localMinter = localMinter_;\n }\n\n function setRemoteTokenMessenger(uint32 remoteDomain, bytes32 remoteTokenMessenger_) external {\n remoteTokenMessenger[remoteDomain] = remoteTokenMessenger_;\n }\n\n function depositForBurnWithCaller(\n uint256 amount,\n uint32 destinationDomain,\n bytes32 mintRecipient,\n address burnToken,\n bytes32 destinationCaller\n ) external returns (uint64 nonce) {\n IERC20(burnToken).safeTransferFrom(msg.sender, localMinter, amount);\n ITokenMinter(localMinter).burn(burnToken, amount);\n bytes memory messageBody = formatTokenMessage(amount, mintRecipient, burnToken);\n nonce = IMessageTransmitter(localMessageTransmitter).sendMessageWithCaller(\n destinationDomain,\n remoteTokenMessenger[destinationDomain],\n destinationCaller,\n messageBody\n );\n emit DepositForBurn({\n nonce: nonce,\n burnToken: burnToken,\n amount: amount,\n depositor: msg.sender,\n mintRecipient: mintRecipient,\n destinationDomain: destinationDomain,\n destinationTokenMessenger: remoteTokenMessenger[destinationDomain],\n destinationCaller: destinationCaller\n });\n }\n\n function handleReceiveMessage(\n uint32 remoteDomain,\n bytes32 sender,\n bytes calldata messageBody\n ) external returns (bool success) {\n require(msg.sender == localMessageTransmitter, \"Invalid message transmitter\");\n require(sender == remoteTokenMessenger[remoteDomain], \"Remote TokenMessenger unsupported\");\n (uint256 amount, bytes32 mintRecipient, bytes32 burnToken) = abi.decode(\n messageBody,\n (uint256, bytes32, bytes32)\n );\n address mintToken = ITokenMinter(localMinter).mint(\n remoteDomain,\n burnToken,\n address(uint160(uint256(mintRecipient))),\n amount\n );\n emit MintAndWithdraw({\n mintRecipient: address(uint160(uint256(mintRecipient))),\n amount: amount,\n mintToken: mintToken\n });\n return true;\n }\n\n function formatTokenMessage(\n uint256 amount,\n bytes32 mintRecipient,\n address burnToken\n ) public pure returns (bytes memory tokenMessage) {\n return abi.encode(amount, mintRecipient, bytes32(uint256(uint160(burnToken))));\n }\n}\n","language":"Solidity","languageVersion":"0.8.17","compilerVersion":"0.8.17","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../","srcMap":"","srcMapRuntime":"","abiDefinition":[{"inputs":[],"name":"localDomain","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"nextAvailableNonce","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"message","type":"bytes"},{"internalType":"bytes","name":"signature","type":"bytes"}],"name":"receiveMessage","outputs":[{"internalType":"bool","name":"success","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint32","name":"destinationDomain","type":"uint32"},{"internalType":"bytes32","name":"recipient","type":"bytes32"},{"internalType":"bytes32","name":"destinationCaller","type":"bytes32"},{"internalType":"bytes","name":"messageBody","type":"bytes"}],"name":"sendMessageWithCaller","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"nonpayable","type":"function"}],"userDoc":{"kind":"user","methods":{"receiveMessage(bytes,bytes)":{"notice":"Receives an incoming message, validating the header and passing the body to application-specific handler."},"sendMessageWithCaller(uint32,bytes32,bytes32,bytes)":{"notice":"Sends an outgoing message from the source domain, with a specified caller on the destination domain."}},"version":1},"developerDoc":{"kind":"dev","methods":{"receiveMessage(bytes,bytes)":{"params":{"message":"The message raw bytes","signature":"The message signature"},"returns":{"success":"bool, true if successful"}},"sendMessageWithCaller(uint32,bytes32,bytes32,bytes)":{"details":"Increment nonce, format the message, and emit `MessageSent` event with message information. WARNING: if the `destinationCaller` does not represent a valid address as bytes32, then it will not be possible to broadcast the message on the destination domain. This is an advanced feature, and the standard sendMessage() should be preferred for use cases where a specific destination caller is not required.","params":{"destinationCaller":"caller on the destination domain, as bytes32","destinationDomain":"Domain of destination chain","messageBody":"Raw bytes content of message","recipient":"Address of message recipient on destination domain as bytes32"},"returns":{"_0":"nonce reserved by message"}}},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.17+commit.8df45f5f\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[],\"name\":\"localDomain\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"nextAvailableNonce\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"\",\"type\":\"uint64\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"message\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"signature\",\"type\":\"bytes\"}],\"name\":\"receiveMessage\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"success\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"destinationDomain\",\"type\":\"uint32\"},{\"internalType\":\"bytes32\",\"name\":\"recipient\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"destinationCaller\",\"type\":\"bytes32\"},{\"internalType\":\"bytes\",\"name\":\"messageBody\",\"type\":\"bytes\"}],\"name\":\"sendMessageWithCaller\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"\",\"type\":\"uint64\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{\"receiveMessage(bytes,bytes)\":{\"params\":{\"message\":\"The message raw bytes\",\"signature\":\"The message signature\"},\"returns\":{\"success\":\"bool, true if successful\"}},\"sendMessageWithCaller(uint32,bytes32,bytes32,bytes)\":{\"details\":\"Increment nonce, format the message, and emit `MessageSent` event with message information. WARNING: if the `destinationCaller` does not represent a valid address as bytes32, then it will not be possible to broadcast the message on the destination domain. This is an advanced feature, and the standard sendMessage() should be preferred for use cases where a specific destination caller is not required.\",\"params\":{\"destinationCaller\":\"caller on the destination domain, as bytes32\",\"destinationDomain\":\"Domain of destination chain\",\"messageBody\":\"Raw bytes content of message\",\"recipient\":\"Address of message recipient on destination domain as bytes32\"},\"returns\":{\"_0\":\"nonce reserved by message\"}}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"receiveMessage(bytes,bytes)\":{\"notice\":\"Receives an incoming message, validating the header and passing the body to application-specific handler.\"},\"sendMessageWithCaller(uint32,bytes32,bytes32,bytes)\":{\"notice\":\"Sends an outgoing message from the source domain, with a specified caller on the destination domain.\"}},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/MockTokenMessenger.sol\":\"IMessageTransmitter\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/MockTokenMessenger.sol\":{\"keccak256\":\"0x676112f99e502493a5f5dddf4043b92d8baf8accb1bdc704a0e77529ddba46d6\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://b7f4c1c133460718570f7c97bf1f098cc47625b54e419be0bc87dcbc1863e3ce\",\"dweb:/ipfs/QmdAEfnnzhMPUcAaAGnG9zeY8KPpnLrR9PKx4VMSqb6Usx\"]}},\"version\":1}"},"hashes":{"localDomain()":"8d3638f4","nextAvailableNonce()":"8371744e","receiveMessage(bytes,bytes)":"57ecfd28","sendMessageWithCaller(uint32,bytes32,bytes32,bytes)":"f7259a75"}},"solidity/MockTokenMessenger.sol:ITokenMessenger":{"code":"0x","runtime-code":"0x","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity 0.8.17;\n\nabstract contract TokenMessengerEvents {\n /**\n * @notice Emitted when a DepositForBurn message is sent\n * @param nonce unique nonce reserved by message\n * @param burnToken address of token burnt on source domain\n * @param amount deposit amount\n * @param depositor address where deposit is transferred from\n * @param mintRecipient address receiving minted tokens on destination domain as bytes32\n * @param destinationDomain destination domain\n * @param destinationTokenMessenger address of TokenMessenger on destination domain as bytes32\n * @param destinationCaller authorized caller as bytes32 of receiveMessage() on destination domain, if not equal to bytes32(0).\n * If equal to bytes32(0), any address can call receiveMessage().\n */\n event DepositForBurn(\n uint64 indexed nonce,\n address indexed burnToken,\n uint256 amount,\n address indexed depositor,\n bytes32 mintRecipient,\n uint32 destinationDomain,\n bytes32 destinationTokenMessenger,\n bytes32 destinationCaller\n );\n\n /**\n * @notice Emitted when tokens are minted\n * @param mintRecipient recipient address of minted tokens\n * @param amount amount of minted tokens\n * @param mintToken contract address of minted token\n */\n event MintAndWithdraw(address indexed mintRecipient, uint256 amount, address indexed mintToken);\n}\n\ninterface IMessageTransmitter {\n /**\n * @notice Receives an incoming message, validating the header and passing\n * the body to application-specific handler.\n * @param message The message raw bytes\n * @param signature The message signature\n * @return success bool, true if successful\n */\n function receiveMessage(bytes calldata message, bytes calldata signature) external returns (bool success);\n\n /**\n * @notice Sends an outgoing message from the source domain, with a specified caller on the\n * destination domain.\n * @dev Increment nonce, format the message, and emit `MessageSent` event with message information.\n * WARNING: if the `destinationCaller` does not represent a valid address as bytes32, then it will not be possible\n * to broadcast the message on the destination domain. This is an advanced feature, and the standard\n * sendMessage() should be preferred for use cases where a specific destination caller is not required.\n * @param destinationDomain Domain of destination chain\n * @param recipient Address of message recipient on destination domain as bytes32\n * @param destinationCaller caller on the destination domain, as bytes32\n * @param messageBody Raw bytes content of message\n * @return nonce reserved by message\n */\n function sendMessageWithCaller(\n uint32 destinationDomain,\n bytes32 recipient,\n bytes32 destinationCaller,\n bytes calldata messageBody\n ) external returns (uint64);\n\n // ═══════════════════════════════════════════════════ VIEWS ═══════════════════════════════════════════════════════\n\n // Domain of chain on which the contract is deployed\n function localDomain() external view returns (uint32);\n\n // Next available nonce from this source domain\n function nextAvailableNonce() external view returns (uint64);\n}\n\ninterface ITokenMessenger {\n /**\n * @notice Deposits and burns tokens from sender to be minted on destination domain. The mint\n * on the destination domain must be called by `destinationCaller`.\n * WARNING: if the `destinationCaller` does not represent a valid address as bytes32, then it will not be possible\n * to broadcast the message on the destination domain. This is an advanced feature, and the standard\n * depositForBurn() should be preferred for use cases where a specific destination caller is not required.\n * Emits a `DepositForBurn` event.\n * @dev reverts if:\n * - given destinationCaller is zero address\n * - given burnToken is not supported\n * - given destinationDomain has no TokenMessenger registered\n * - transferFrom() reverts. For example, if sender's burnToken balance or approved allowance\n * to this contract is less than `amount`.\n * - burn() reverts. For example, if `amount` is 0.\n * - MessageTransmitter returns false or reverts.\n * @param amount amount of tokens to burn\n * @param destinationDomain destination domain\n * @param mintRecipient address of mint recipient on destination domain\n * @param burnToken address of contract to burn deposited tokens, on local domain\n * @param destinationCaller caller on the destination domain, as bytes32\n * @return nonce unique nonce reserved by message\n */\n function depositForBurnWithCaller(\n uint256 amount,\n uint32 destinationDomain,\n bytes32 mintRecipient,\n address burnToken,\n bytes32 destinationCaller\n ) external returns (uint64 nonce);\n\n /**\n * @notice Handles an incoming message received by the local MessageTransmitter,\n * and takes the appropriate action. For a burn message, mints the\n * associated token to the requested recipient on the local domain.\n * @dev Validates the local sender is the local MessageTransmitter, and the\n * remote sender is a registered remote TokenMessenger for `remoteDomain`.\n * @param remoteDomain The domain where the message originated from.\n * @param sender The sender of the message (remote TokenMessenger).\n * @param messageBody The message body bytes.\n * @return success Bool, true if successful.\n */\n function handleReceiveMessage(\n uint32 remoteDomain,\n bytes32 sender,\n bytes calldata messageBody\n ) external returns (bool success);\n\n // ═══════════════════════════════════════════════════ VIEWS ═══════════════════════════════════════════════════════\n\n // Local Message Transmitter responsible for sending and receiving messages to/from remote domains\n function localMessageTransmitter() external view returns (address);\n\n // Minter responsible for minting and burning tokens on the local domain\n function localMinter() external view returns (address);\n}\n\ninterface ITokenMinter {\n /**\n * @notice Mints `amount` of local tokens corresponding to the\n * given (`sourceDomain`, `burnToken`) pair, to `to` address.\n * @dev reverts if the (`sourceDomain`, `burnToken`) pair does not\n * map to a nonzero local token address. This mapping can be queried using\n * getLocalToken().\n * @param sourceDomain Source domain where `burnToken` was burned.\n * @param burnToken Burned token address as bytes32.\n * @param to Address to receive minted tokens, corresponding to `burnToken`,\n * on this domain.\n * @param amount Amount of tokens to mint. Must be less than or equal\n * to the minterAllowance of this TokenMinter for given `_mintToken`.\n * @return mintToken token minted.\n */\n function mint(\n uint32 sourceDomain,\n bytes32 burnToken,\n address to,\n uint256 amount\n ) external returns (address mintToken);\n\n /**\n * @notice Burn tokens owned by this ITokenMinter.\n * @param burnToken burnable token.\n * @param amount amount of tokens to burn. Must be less than or equal to this ITokenMinter's\n * account balance of the given `_burnToken`.\n */\n function burn(address burnToken, uint256 amount) external;\n\n /**\n * @notice Get the local token associated with the given remote domain and token.\n * @param remoteDomain Remote domain\n * @param remoteToken Remote token\n * @return local token address\n */\n function getLocalToken(uint32 remoteDomain, bytes32 remoteToken) external view returns (address);\n\n // local token (address) =\u003e maximum burn amounts per message\n function burnLimitsPerMessage(address token) external view returns (uint256);\n}\n\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/utils/SafeERC20.sol)\n\n// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\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(\n address from,\n address to,\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\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\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 * [IMPORTANT]\n * ====\n * You shouldn't rely on `isContract` to protect against flash loan attacks!\n *\n * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\n * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\n * constructor.\n * ====\n */\n function isContract(address account) internal view returns (bool) {\n // This method relies on extcodesize/address.code.length, which returns 0\n // for contracts in construction, since the code is only stored at the end\n // of the constructor execution.\n\n return account.code.length \u003e 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 \u003e= amount, \"Address: insufficient balance\");\n\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(\n address target,\n bytes memory data,\n string memory errorMessage\n ) 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(\n address target,\n bytes memory data,\n uint256 value\n ) 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(\n address target,\n bytes memory data,\n uint256 value,\n string memory errorMessage\n ) internal returns (bytes memory) {\n require(address(this).balance \u003e= value, \"Address: insufficient balance for call\");\n require(isContract(target), \"Address: call to non-contract\");\n\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(\n address target,\n bytes memory data,\n string memory errorMessage\n ) internal view returns (bytes memory) {\n require(isContract(target), \"Address: static call to non-contract\");\n\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResult(success, returndata, errorMessage);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n *\n * _Available since v3.4._\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionDelegateCall(target, data, \"Address: low-level delegate call failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n * but performing a delegate call.\n *\n * _Available since v3.4._\n */\n function functionDelegateCall(\n address target,\n bytes memory data,\n string memory errorMessage\n ) internal returns (bytes memory) {\n require(isContract(target), \"Address: delegate call to non-contract\");\n\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResult(success, returndata, errorMessage);\n }\n\n /**\n * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\n * revert reason using the provided one.\n *\n * _Available since v4.3._\n */\n function verifyCallResult(\n bool success,\n bytes memory returndata,\n string memory errorMessage\n ) internal 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 \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n\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\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n function safeTransfer(\n IERC20 token,\n address to,\n uint256 value\n ) internal {\n _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\n }\n\n function safeTransferFrom(\n IERC20 token,\n address from,\n address to,\n uint256 value\n ) internal {\n _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));\n }\n\n /**\n * @dev Deprecated. This function has issues similar to the ones found in\n * {IERC20-approve}, and its usage is discouraged.\n *\n * Whenever possible, use {safeIncreaseAllowance} and\n * {safeDecreaseAllowance} instead.\n */\n function safeApprove(\n IERC20 token,\n address spender,\n uint256 value\n ) internal {\n // safeApprove should only be called when setting an initial allowance,\n // or when resetting it to zero. To increase and decrease it, use\n // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\n require(\n (value == 0) || (token.allowance(address(this), spender) == 0),\n \"SafeERC20: approve from non-zero to non-zero allowance\"\n );\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\n }\n\n function safeIncreaseAllowance(\n IERC20 token,\n address spender,\n uint256 value\n ) internal {\n uint256 newAllowance = token.allowance(address(this), spender) + value;\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\n }\n\n function safeDecreaseAllowance(\n IERC20 token,\n address spender,\n uint256 value\n ) internal {\n unchecked {\n uint256 oldAllowance = token.allowance(address(this), spender);\n require(oldAllowance \u003e= value, \"SafeERC20: decreased allowance below zero\");\n uint256 newAllowance = oldAllowance - value;\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data, \"SafeERC20: low-level call failed\");\n if (returndata.length \u003e 0) {\n // Return data is optional\n require(abi.decode(returndata, (bool)), \"SafeERC20: ERC20 operation did not succeed\");\n }\n }\n}\n\ncontract MockTokenMessenger is TokenMessengerEvents, ITokenMessenger {\n using SafeERC20 for IERC20;\n\n address public override localMessageTransmitter;\n address public override localMinter;\n mapping(uint32 =\u003e bytes32) public remoteTokenMessenger;\n\n constructor(address localMessageTransmitter_) {\n localMessageTransmitter = localMessageTransmitter_;\n }\n\n function setLocalMinter(address localMinter_) external {\n localMinter = localMinter_;\n }\n\n function setRemoteTokenMessenger(uint32 remoteDomain, bytes32 remoteTokenMessenger_) external {\n remoteTokenMessenger[remoteDomain] = remoteTokenMessenger_;\n }\n\n function depositForBurnWithCaller(\n uint256 amount,\n uint32 destinationDomain,\n bytes32 mintRecipient,\n address burnToken,\n bytes32 destinationCaller\n ) external returns (uint64 nonce) {\n IERC20(burnToken).safeTransferFrom(msg.sender, localMinter, amount);\n ITokenMinter(localMinter).burn(burnToken, amount);\n bytes memory messageBody = formatTokenMessage(amount, mintRecipient, burnToken);\n nonce = IMessageTransmitter(localMessageTransmitter).sendMessageWithCaller(\n destinationDomain,\n remoteTokenMessenger[destinationDomain],\n destinationCaller,\n messageBody\n );\n emit DepositForBurn({\n nonce: nonce,\n burnToken: burnToken,\n amount: amount,\n depositor: msg.sender,\n mintRecipient: mintRecipient,\n destinationDomain: destinationDomain,\n destinationTokenMessenger: remoteTokenMessenger[destinationDomain],\n destinationCaller: destinationCaller\n });\n }\n\n function handleReceiveMessage(\n uint32 remoteDomain,\n bytes32 sender,\n bytes calldata messageBody\n ) external returns (bool success) {\n require(msg.sender == localMessageTransmitter, \"Invalid message transmitter\");\n require(sender == remoteTokenMessenger[remoteDomain], \"Remote TokenMessenger unsupported\");\n (uint256 amount, bytes32 mintRecipient, bytes32 burnToken) = abi.decode(\n messageBody,\n (uint256, bytes32, bytes32)\n );\n address mintToken = ITokenMinter(localMinter).mint(\n remoteDomain,\n burnToken,\n address(uint160(uint256(mintRecipient))),\n amount\n );\n emit MintAndWithdraw({\n mintRecipient: address(uint160(uint256(mintRecipient))),\n amount: amount,\n mintToken: mintToken\n });\n return true;\n }\n\n function formatTokenMessage(\n uint256 amount,\n bytes32 mintRecipient,\n address burnToken\n ) public pure returns (bytes memory tokenMessage) {\n return abi.encode(amount, mintRecipient, bytes32(uint256(uint160(burnToken))));\n }\n}\n","language":"Solidity","languageVersion":"0.8.17","compilerVersion":"0.8.17","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../","srcMap":"","srcMapRuntime":"","abiDefinition":[{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint32","name":"destinationDomain","type":"uint32"},{"internalType":"bytes32","name":"mintRecipient","type":"bytes32"},{"internalType":"address","name":"burnToken","type":"address"},{"internalType":"bytes32","name":"destinationCaller","type":"bytes32"}],"name":"depositForBurnWithCaller","outputs":[{"internalType":"uint64","name":"nonce","type":"uint64"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint32","name":"remoteDomain","type":"uint32"},{"internalType":"bytes32","name":"sender","type":"bytes32"},{"internalType":"bytes","name":"messageBody","type":"bytes"}],"name":"handleReceiveMessage","outputs":[{"internalType":"bool","name":"success","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"localMessageTransmitter","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"localMinter","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"}],"userDoc":{"kind":"user","methods":{"depositForBurnWithCaller(uint256,uint32,bytes32,address,bytes32)":{"notice":"Deposits and burns tokens from sender to be minted on destination domain. The mint on the destination domain must be called by `destinationCaller`. WARNING: if the `destinationCaller` does not represent a valid address as bytes32, then it will not be possible to broadcast the message on the destination domain. This is an advanced feature, and the standard depositForBurn() should be preferred for use cases where a specific destination caller is not required. Emits a `DepositForBurn` event."},"handleReceiveMessage(uint32,bytes32,bytes)":{"notice":"Handles an incoming message received by the local MessageTransmitter, and takes the appropriate action. For a burn message, mints the associated token to the requested recipient on the local domain."}},"version":1},"developerDoc":{"kind":"dev","methods":{"depositForBurnWithCaller(uint256,uint32,bytes32,address,bytes32)":{"details":"reverts if: - given destinationCaller is zero address - given burnToken is not supported - given destinationDomain has no TokenMessenger registered - transferFrom() reverts. For example, if sender's burnToken balance or approved allowance to this contract is less than `amount`. - burn() reverts. For example, if `amount` is 0. - MessageTransmitter returns false or reverts.","params":{"amount":"amount of tokens to burn","burnToken":"address of contract to burn deposited tokens, on local domain","destinationCaller":"caller on the destination domain, as bytes32","destinationDomain":"destination domain","mintRecipient":"address of mint recipient on destination domain"},"returns":{"nonce":"unique nonce reserved by message"}},"handleReceiveMessage(uint32,bytes32,bytes)":{"details":"Validates the local sender is the local MessageTransmitter, and the remote sender is a registered remote TokenMessenger for `remoteDomain`.","params":{"messageBody":"The message body bytes.","remoteDomain":"The domain where the message originated from.","sender":"The sender of the message (remote TokenMessenger)."},"returns":{"success":"Bool, true if successful."}}},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.17+commit.8df45f5f\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint32\",\"name\":\"destinationDomain\",\"type\":\"uint32\"},{\"internalType\":\"bytes32\",\"name\":\"mintRecipient\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"burnToken\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"destinationCaller\",\"type\":\"bytes32\"}],\"name\":\"depositForBurnWithCaller\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"nonce\",\"type\":\"uint64\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"remoteDomain\",\"type\":\"uint32\"},{\"internalType\":\"bytes32\",\"name\":\"sender\",\"type\":\"bytes32\"},{\"internalType\":\"bytes\",\"name\":\"messageBody\",\"type\":\"bytes\"}],\"name\":\"handleReceiveMessage\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"success\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"localMessageTransmitter\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"localMinter\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{\"depositForBurnWithCaller(uint256,uint32,bytes32,address,bytes32)\":{\"details\":\"reverts if: - given destinationCaller is zero address - given burnToken is not supported - given destinationDomain has no TokenMessenger registered - transferFrom() reverts. For example, if sender's burnToken balance or approved allowance to this contract is less than `amount`. - burn() reverts. For example, if `amount` is 0. - MessageTransmitter returns false or reverts.\",\"params\":{\"amount\":\"amount of tokens to burn\",\"burnToken\":\"address of contract to burn deposited tokens, on local domain\",\"destinationCaller\":\"caller on the destination domain, as bytes32\",\"destinationDomain\":\"destination domain\",\"mintRecipient\":\"address of mint recipient on destination domain\"},\"returns\":{\"nonce\":\"unique nonce reserved by message\"}},\"handleReceiveMessage(uint32,bytes32,bytes)\":{\"details\":\"Validates the local sender is the local MessageTransmitter, and the remote sender is a registered remote TokenMessenger for `remoteDomain`.\",\"params\":{\"messageBody\":\"The message body bytes.\",\"remoteDomain\":\"The domain where the message originated from.\",\"sender\":\"The sender of the message (remote TokenMessenger).\"},\"returns\":{\"success\":\"Bool, true if successful.\"}}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"depositForBurnWithCaller(uint256,uint32,bytes32,address,bytes32)\":{\"notice\":\"Deposits and burns tokens from sender to be minted on destination domain. The mint on the destination domain must be called by `destinationCaller`. WARNING: if the `destinationCaller` does not represent a valid address as bytes32, then it will not be possible to broadcast the message on the destination domain. This is an advanced feature, and the standard depositForBurn() should be preferred for use cases where a specific destination caller is not required. Emits a `DepositForBurn` event.\"},\"handleReceiveMessage(uint32,bytes32,bytes)\":{\"notice\":\"Handles an incoming message received by the local MessageTransmitter, and takes the appropriate action. For a burn message, mints the associated token to the requested recipient on the local domain.\"}},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/MockTokenMessenger.sol\":\"ITokenMessenger\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/MockTokenMessenger.sol\":{\"keccak256\":\"0x676112f99e502493a5f5dddf4043b92d8baf8accb1bdc704a0e77529ddba46d6\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://b7f4c1c133460718570f7c97bf1f098cc47625b54e419be0bc87dcbc1863e3ce\",\"dweb:/ipfs/QmdAEfnnzhMPUcAaAGnG9zeY8KPpnLrR9PKx4VMSqb6Usx\"]}},\"version\":1}"},"hashes":{"depositForBurnWithCaller(uint256,uint32,bytes32,address,bytes32)":"f856ddb6","handleReceiveMessage(uint32,bytes32,bytes)":"96abeb70","localMessageTransmitter()":"2c121921","localMinter()":"cb75c11c"}},"solidity/MockTokenMessenger.sol:ITokenMinter":{"code":"0x","runtime-code":"0x","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity 0.8.17;\n\nabstract contract TokenMessengerEvents {\n /**\n * @notice Emitted when a DepositForBurn message is sent\n * @param nonce unique nonce reserved by message\n * @param burnToken address of token burnt on source domain\n * @param amount deposit amount\n * @param depositor address where deposit is transferred from\n * @param mintRecipient address receiving minted tokens on destination domain as bytes32\n * @param destinationDomain destination domain\n * @param destinationTokenMessenger address of TokenMessenger on destination domain as bytes32\n * @param destinationCaller authorized caller as bytes32 of receiveMessage() on destination domain, if not equal to bytes32(0).\n * If equal to bytes32(0), any address can call receiveMessage().\n */\n event DepositForBurn(\n uint64 indexed nonce,\n address indexed burnToken,\n uint256 amount,\n address indexed depositor,\n bytes32 mintRecipient,\n uint32 destinationDomain,\n bytes32 destinationTokenMessenger,\n bytes32 destinationCaller\n );\n\n /**\n * @notice Emitted when tokens are minted\n * @param mintRecipient recipient address of minted tokens\n * @param amount amount of minted tokens\n * @param mintToken contract address of minted token\n */\n event MintAndWithdraw(address indexed mintRecipient, uint256 amount, address indexed mintToken);\n}\n\ninterface IMessageTransmitter {\n /**\n * @notice Receives an incoming message, validating the header and passing\n * the body to application-specific handler.\n * @param message The message raw bytes\n * @param signature The message signature\n * @return success bool, true if successful\n */\n function receiveMessage(bytes calldata message, bytes calldata signature) external returns (bool success);\n\n /**\n * @notice Sends an outgoing message from the source domain, with a specified caller on the\n * destination domain.\n * @dev Increment nonce, format the message, and emit `MessageSent` event with message information.\n * WARNING: if the `destinationCaller` does not represent a valid address as bytes32, then it will not be possible\n * to broadcast the message on the destination domain. This is an advanced feature, and the standard\n * sendMessage() should be preferred for use cases where a specific destination caller is not required.\n * @param destinationDomain Domain of destination chain\n * @param recipient Address of message recipient on destination domain as bytes32\n * @param destinationCaller caller on the destination domain, as bytes32\n * @param messageBody Raw bytes content of message\n * @return nonce reserved by message\n */\n function sendMessageWithCaller(\n uint32 destinationDomain,\n bytes32 recipient,\n bytes32 destinationCaller,\n bytes calldata messageBody\n ) external returns (uint64);\n\n // ═══════════════════════════════════════════════════ VIEWS ═══════════════════════════════════════════════════════\n\n // Domain of chain on which the contract is deployed\n function localDomain() external view returns (uint32);\n\n // Next available nonce from this source domain\n function nextAvailableNonce() external view returns (uint64);\n}\n\ninterface ITokenMessenger {\n /**\n * @notice Deposits and burns tokens from sender to be minted on destination domain. The mint\n * on the destination domain must be called by `destinationCaller`.\n * WARNING: if the `destinationCaller` does not represent a valid address as bytes32, then it will not be possible\n * to broadcast the message on the destination domain. This is an advanced feature, and the standard\n * depositForBurn() should be preferred for use cases where a specific destination caller is not required.\n * Emits a `DepositForBurn` event.\n * @dev reverts if:\n * - given destinationCaller is zero address\n * - given burnToken is not supported\n * - given destinationDomain has no TokenMessenger registered\n * - transferFrom() reverts. For example, if sender's burnToken balance or approved allowance\n * to this contract is less than `amount`.\n * - burn() reverts. For example, if `amount` is 0.\n * - MessageTransmitter returns false or reverts.\n * @param amount amount of tokens to burn\n * @param destinationDomain destination domain\n * @param mintRecipient address of mint recipient on destination domain\n * @param burnToken address of contract to burn deposited tokens, on local domain\n * @param destinationCaller caller on the destination domain, as bytes32\n * @return nonce unique nonce reserved by message\n */\n function depositForBurnWithCaller(\n uint256 amount,\n uint32 destinationDomain,\n bytes32 mintRecipient,\n address burnToken,\n bytes32 destinationCaller\n ) external returns (uint64 nonce);\n\n /**\n * @notice Handles an incoming message received by the local MessageTransmitter,\n * and takes the appropriate action. For a burn message, mints the\n * associated token to the requested recipient on the local domain.\n * @dev Validates the local sender is the local MessageTransmitter, and the\n * remote sender is a registered remote TokenMessenger for `remoteDomain`.\n * @param remoteDomain The domain where the message originated from.\n * @param sender The sender of the message (remote TokenMessenger).\n * @param messageBody The message body bytes.\n * @return success Bool, true if successful.\n */\n function handleReceiveMessage(\n uint32 remoteDomain,\n bytes32 sender,\n bytes calldata messageBody\n ) external returns (bool success);\n\n // ═══════════════════════════════════════════════════ VIEWS ═══════════════════════════════════════════════════════\n\n // Local Message Transmitter responsible for sending and receiving messages to/from remote domains\n function localMessageTransmitter() external view returns (address);\n\n // Minter responsible for minting and burning tokens on the local domain\n function localMinter() external view returns (address);\n}\n\ninterface ITokenMinter {\n /**\n * @notice Mints `amount` of local tokens corresponding to the\n * given (`sourceDomain`, `burnToken`) pair, to `to` address.\n * @dev reverts if the (`sourceDomain`, `burnToken`) pair does not\n * map to a nonzero local token address. This mapping can be queried using\n * getLocalToken().\n * @param sourceDomain Source domain where `burnToken` was burned.\n * @param burnToken Burned token address as bytes32.\n * @param to Address to receive minted tokens, corresponding to `burnToken`,\n * on this domain.\n * @param amount Amount of tokens to mint. Must be less than or equal\n * to the minterAllowance of this TokenMinter for given `_mintToken`.\n * @return mintToken token minted.\n */\n function mint(\n uint32 sourceDomain,\n bytes32 burnToken,\n address to,\n uint256 amount\n ) external returns (address mintToken);\n\n /**\n * @notice Burn tokens owned by this ITokenMinter.\n * @param burnToken burnable token.\n * @param amount amount of tokens to burn. Must be less than or equal to this ITokenMinter's\n * account balance of the given `_burnToken`.\n */\n function burn(address burnToken, uint256 amount) external;\n\n /**\n * @notice Get the local token associated with the given remote domain and token.\n * @param remoteDomain Remote domain\n * @param remoteToken Remote token\n * @return local token address\n */\n function getLocalToken(uint32 remoteDomain, bytes32 remoteToken) external view returns (address);\n\n // local token (address) =\u003e maximum burn amounts per message\n function burnLimitsPerMessage(address token) external view returns (uint256);\n}\n\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/utils/SafeERC20.sol)\n\n// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\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(\n address from,\n address to,\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\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\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 * [IMPORTANT]\n * ====\n * You shouldn't rely on `isContract` to protect against flash loan attacks!\n *\n * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\n * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\n * constructor.\n * ====\n */\n function isContract(address account) internal view returns (bool) {\n // This method relies on extcodesize/address.code.length, which returns 0\n // for contracts in construction, since the code is only stored at the end\n // of the constructor execution.\n\n return account.code.length \u003e 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 \u003e= amount, \"Address: insufficient balance\");\n\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(\n address target,\n bytes memory data,\n string memory errorMessage\n ) 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(\n address target,\n bytes memory data,\n uint256 value\n ) 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(\n address target,\n bytes memory data,\n uint256 value,\n string memory errorMessage\n ) internal returns (bytes memory) {\n require(address(this).balance \u003e= value, \"Address: insufficient balance for call\");\n require(isContract(target), \"Address: call to non-contract\");\n\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(\n address target,\n bytes memory data,\n string memory errorMessage\n ) internal view returns (bytes memory) {\n require(isContract(target), \"Address: static call to non-contract\");\n\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResult(success, returndata, errorMessage);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n *\n * _Available since v3.4._\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionDelegateCall(target, data, \"Address: low-level delegate call failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n * but performing a delegate call.\n *\n * _Available since v3.4._\n */\n function functionDelegateCall(\n address target,\n bytes memory data,\n string memory errorMessage\n ) internal returns (bytes memory) {\n require(isContract(target), \"Address: delegate call to non-contract\");\n\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResult(success, returndata, errorMessage);\n }\n\n /**\n * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\n * revert reason using the provided one.\n *\n * _Available since v4.3._\n */\n function verifyCallResult(\n bool success,\n bytes memory returndata,\n string memory errorMessage\n ) internal 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 \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n\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\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n function safeTransfer(\n IERC20 token,\n address to,\n uint256 value\n ) internal {\n _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\n }\n\n function safeTransferFrom(\n IERC20 token,\n address from,\n address to,\n uint256 value\n ) internal {\n _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));\n }\n\n /**\n * @dev Deprecated. This function has issues similar to the ones found in\n * {IERC20-approve}, and its usage is discouraged.\n *\n * Whenever possible, use {safeIncreaseAllowance} and\n * {safeDecreaseAllowance} instead.\n */\n function safeApprove(\n IERC20 token,\n address spender,\n uint256 value\n ) internal {\n // safeApprove should only be called when setting an initial allowance,\n // or when resetting it to zero. To increase and decrease it, use\n // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\n require(\n (value == 0) || (token.allowance(address(this), spender) == 0),\n \"SafeERC20: approve from non-zero to non-zero allowance\"\n );\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\n }\n\n function safeIncreaseAllowance(\n IERC20 token,\n address spender,\n uint256 value\n ) internal {\n uint256 newAllowance = token.allowance(address(this), spender) + value;\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\n }\n\n function safeDecreaseAllowance(\n IERC20 token,\n address spender,\n uint256 value\n ) internal {\n unchecked {\n uint256 oldAllowance = token.allowance(address(this), spender);\n require(oldAllowance \u003e= value, \"SafeERC20: decreased allowance below zero\");\n uint256 newAllowance = oldAllowance - value;\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data, \"SafeERC20: low-level call failed\");\n if (returndata.length \u003e 0) {\n // Return data is optional\n require(abi.decode(returndata, (bool)), \"SafeERC20: ERC20 operation did not succeed\");\n }\n }\n}\n\ncontract MockTokenMessenger is TokenMessengerEvents, ITokenMessenger {\n using SafeERC20 for IERC20;\n\n address public override localMessageTransmitter;\n address public override localMinter;\n mapping(uint32 =\u003e bytes32) public remoteTokenMessenger;\n\n constructor(address localMessageTransmitter_) {\n localMessageTransmitter = localMessageTransmitter_;\n }\n\n function setLocalMinter(address localMinter_) external {\n localMinter = localMinter_;\n }\n\n function setRemoteTokenMessenger(uint32 remoteDomain, bytes32 remoteTokenMessenger_) external {\n remoteTokenMessenger[remoteDomain] = remoteTokenMessenger_;\n }\n\n function depositForBurnWithCaller(\n uint256 amount,\n uint32 destinationDomain,\n bytes32 mintRecipient,\n address burnToken,\n bytes32 destinationCaller\n ) external returns (uint64 nonce) {\n IERC20(burnToken).safeTransferFrom(msg.sender, localMinter, amount);\n ITokenMinter(localMinter).burn(burnToken, amount);\n bytes memory messageBody = formatTokenMessage(amount, mintRecipient, burnToken);\n nonce = IMessageTransmitter(localMessageTransmitter).sendMessageWithCaller(\n destinationDomain,\n remoteTokenMessenger[destinationDomain],\n destinationCaller,\n messageBody\n );\n emit DepositForBurn({\n nonce: nonce,\n burnToken: burnToken,\n amount: amount,\n depositor: msg.sender,\n mintRecipient: mintRecipient,\n destinationDomain: destinationDomain,\n destinationTokenMessenger: remoteTokenMessenger[destinationDomain],\n destinationCaller: destinationCaller\n });\n }\n\n function handleReceiveMessage(\n uint32 remoteDomain,\n bytes32 sender,\n bytes calldata messageBody\n ) external returns (bool success) {\n require(msg.sender == localMessageTransmitter, \"Invalid message transmitter\");\n require(sender == remoteTokenMessenger[remoteDomain], \"Remote TokenMessenger unsupported\");\n (uint256 amount, bytes32 mintRecipient, bytes32 burnToken) = abi.decode(\n messageBody,\n (uint256, bytes32, bytes32)\n );\n address mintToken = ITokenMinter(localMinter).mint(\n remoteDomain,\n burnToken,\n address(uint160(uint256(mintRecipient))),\n amount\n );\n emit MintAndWithdraw({\n mintRecipient: address(uint160(uint256(mintRecipient))),\n amount: amount,\n mintToken: mintToken\n });\n return true;\n }\n\n function formatTokenMessage(\n uint256 amount,\n bytes32 mintRecipient,\n address burnToken\n ) public pure returns (bytes memory tokenMessage) {\n return abi.encode(amount, mintRecipient, bytes32(uint256(uint160(burnToken))));\n }\n}\n","language":"Solidity","languageVersion":"0.8.17","compilerVersion":"0.8.17","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../","srcMap":"","srcMapRuntime":"","abiDefinition":[{"inputs":[{"internalType":"address","name":"burnToken","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"burn","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"burnLimitsPerMessage","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint32","name":"remoteDomain","type":"uint32"},{"internalType":"bytes32","name":"remoteToken","type":"bytes32"}],"name":"getLocalToken","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint32","name":"sourceDomain","type":"uint32"},{"internalType":"bytes32","name":"burnToken","type":"bytes32"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"mint","outputs":[{"internalType":"address","name":"mintToken","type":"address"}],"stateMutability":"nonpayable","type":"function"}],"userDoc":{"kind":"user","methods":{"burn(address,uint256)":{"notice":"Burn tokens owned by this ITokenMinter."},"getLocalToken(uint32,bytes32)":{"notice":"Get the local token associated with the given remote domain and token."},"mint(uint32,bytes32,address,uint256)":{"notice":"Mints `amount` of local tokens corresponding to the given (`sourceDomain`, `burnToken`) pair, to `to` address."}},"version":1},"developerDoc":{"kind":"dev","methods":{"burn(address,uint256)":{"params":{"amount":"amount of tokens to burn. Must be less than or equal to this ITokenMinter's account balance of the given `_burnToken`.","burnToken":"burnable token."}},"getLocalToken(uint32,bytes32)":{"params":{"remoteDomain":"Remote domain","remoteToken":"Remote token"},"returns":{"_0":"local token address"}},"mint(uint32,bytes32,address,uint256)":{"details":"reverts if the (`sourceDomain`, `burnToken`) pair does not map to a nonzero local token address. This mapping can be queried using getLocalToken().","params":{"amount":"Amount of tokens to mint. Must be less than or equal to the minterAllowance of this TokenMinter for given `_mintToken`.","burnToken":"Burned token address as bytes32.","sourceDomain":"Source domain where `burnToken` was burned.","to":"Address to receive minted tokens, corresponding to `burnToken`, on this domain."},"returns":{"mintToken":"token minted."}}},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.17+commit.8df45f5f\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"burnToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"burn\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"}],\"name\":\"burnLimitsPerMessage\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"remoteDomain\",\"type\":\"uint32\"},{\"internalType\":\"bytes32\",\"name\":\"remoteToken\",\"type\":\"bytes32\"}],\"name\":\"getLocalToken\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"sourceDomain\",\"type\":\"uint32\"},{\"internalType\":\"bytes32\",\"name\":\"burnToken\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"mint\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"mintToken\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{\"burn(address,uint256)\":{\"params\":{\"amount\":\"amount of tokens to burn. Must be less than or equal to this ITokenMinter's account balance of the given `_burnToken`.\",\"burnToken\":\"burnable token.\"}},\"getLocalToken(uint32,bytes32)\":{\"params\":{\"remoteDomain\":\"Remote domain\",\"remoteToken\":\"Remote token\"},\"returns\":{\"_0\":\"local token address\"}},\"mint(uint32,bytes32,address,uint256)\":{\"details\":\"reverts if the (`sourceDomain`, `burnToken`) pair does not map to a nonzero local token address. This mapping can be queried using getLocalToken().\",\"params\":{\"amount\":\"Amount of tokens to mint. Must be less than or equal to the minterAllowance of this TokenMinter for given `_mintToken`.\",\"burnToken\":\"Burned token address as bytes32.\",\"sourceDomain\":\"Source domain where `burnToken` was burned.\",\"to\":\"Address to receive minted tokens, corresponding to `burnToken`, on this domain.\"},\"returns\":{\"mintToken\":\"token minted.\"}}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"burn(address,uint256)\":{\"notice\":\"Burn tokens owned by this ITokenMinter.\"},\"getLocalToken(uint32,bytes32)\":{\"notice\":\"Get the local token associated with the given remote domain and token.\"},\"mint(uint32,bytes32,address,uint256)\":{\"notice\":\"Mints `amount` of local tokens corresponding to the given (`sourceDomain`, `burnToken`) pair, to `to` address.\"}},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/MockTokenMessenger.sol\":\"ITokenMinter\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/MockTokenMessenger.sol\":{\"keccak256\":\"0x676112f99e502493a5f5dddf4043b92d8baf8accb1bdc704a0e77529ddba46d6\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://b7f4c1c133460718570f7c97bf1f098cc47625b54e419be0bc87dcbc1863e3ce\",\"dweb:/ipfs/QmdAEfnnzhMPUcAaAGnG9zeY8KPpnLrR9PKx4VMSqb6Usx\"]}},\"version\":1}"},"hashes":{"burn(address,uint256)":"9dc29fac","burnLimitsPerMessage(address)":"a56ec632","getLocalToken(uint32,bytes32)":"78a0565e","mint(uint32,bytes32,address,uint256)":"d54de06f"}},"solidity/MockTokenMessenger.sol:MockTokenMessenger":{"code":"0x608060405234801561001057600080fd5b50604051610e6d380380610e6d83398101604081905261002f91610054565b600080546001600160a01b0319166001600160a01b0392909216919091179055610084565b60006020828403121561006657600080fd5b81516001600160a01b038116811461007d57600080fd5b9392505050565b610dda806100936000396000f3fe608060405234801561001057600080fd5b50600436106100885760003560e01c8063b6aa3fe31161005b578063b6aa3fe314610151578063cb75c11c14610171578063f5af2a4514610191578063f856ddb6146101e657600080fd5b80632c1219211461008d5780636b51d203146100d757806396abeb7014610100578063b35b046414610123575b600080fd5b6000546100ad9073ffffffffffffffffffffffffffffffffffffffff1681565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b6100fe6100e5366004610aa6565b63ffffffff909116600090815260026020526040902055565b005b61011361010e366004610ad0565b610212565b60405190151581526020016100ce565b610143610131366004610b57565b60026020526000908152604090205481565b6040519081526020016100ce565b61016461015f366004610b97565b610482565b6040516100ce9190610c3e565b6001546100ad9073ffffffffffffffffffffffffffffffffffffffff1681565b6100fe61019f366004610c51565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055565b6101f96101f4366004610c6e565b6104d0565b60405167ffffffffffffffff90911681526020016100ce565b6000805473ffffffffffffffffffffffffffffffffffffffff163314610299576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f496e76616c6964206d657373616765207472616e736d6974746572000000000060448201526064015b60405180910390fd5b63ffffffff8516600090815260026020526040902054841461033d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602160248201527f52656d6f746520546f6b656e4d657373656e67657220756e737570706f72746560448201527f64000000000000000000000000000000000000000000000000000000000000006064820152608401610290565b6000808061034d85870187610cbe565b6001546040517fd54de06f00000000000000000000000000000000000000000000000000000000815263ffffffff8d1660048201526024810183905273ffffffffffffffffffffffffffffffffffffffff808516604483015260648201869052949750929550909350600092169063d54de06f906084016020604051808303816000875af11580156103e3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104079190610cea565b90508073ffffffffffffffffffffffffffffffffffffffff168360001c73ffffffffffffffffffffffffffffffffffffffff167f1b2a7ff080b8cb6ff436ce0372e399692bbfb6d4ae5766fd8d58a7b8cc6142e68660405161046b91815260200190565b60405180910390a350600198975050505050505050565b604080516020810185905290810183905273ffffffffffffffffffffffffffffffffffffffff82166060808301919091529060800160405160208183030381529060405290505b9392505050565b6001546000906104fc9073ffffffffffffffffffffffffffffffffffffffff85811691339116896106e1565b6001546040517f9dc29fac00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff85811660048301526024820189905290911690639dc29fac90604401600060405180830381600087803b15801561057057600080fd5b505af1158015610584573d6000803e3d6000fd5b505050506000610595878686610482565b6000805463ffffffff8916825260026020526040918290205491517ff7259a7500000000000000000000000000000000000000000000000000000000815292935073ffffffffffffffffffffffffffffffffffffffff169163f7259a7591610606918a919088908790600401610d07565b6020604051808303816000875af1158015610625573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106499190610d3c565b63ffffffff87166000818152600260209081526040918290205482518c81529182018a905291810192909252606082015260808101859052909250339073ffffffffffffffffffffffffffffffffffffffff86169067ffffffffffffffff8516907f2fa9ca894982930190727e75500a97d8dc500233a5065e0f3126c48fbe0343c09060a00160405180910390a45095945050505050565b6040805173ffffffffffffffffffffffffffffffffffffffff85811660248301528416604482015260648082018490528251808303909101815260849091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f23b872dd0000000000000000000000000000000000000000000000000000000017905261077690859061077c565b50505050565b60006107de826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff1661088d9092919063ffffffff16565b80519091501561088857808060200190518101906107fc9190610d66565b610888576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f742073756363656564000000000000000000000000000000000000000000006064820152608401610290565b505050565b606061089c84846000856108a4565b949350505050565b606082471015610936576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c00000000000000000000000000000000000000000000000000006064820152608401610290565b73ffffffffffffffffffffffffffffffffffffffff85163b6109b4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610290565b6000808673ffffffffffffffffffffffffffffffffffffffff1685876040516109dd9190610d88565b60006040518083038185875af1925050503d8060008114610a1a576040519150601f19603f3d011682016040523d82523d6000602084013e610a1f565b606091505b5091509150610a2f828286610a3a565b979650505050505050565b60608315610a495750816104c9565b825115610a595782518084602001fd5b816040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016102909190610c3e565b803563ffffffff81168114610aa157600080fd5b919050565b60008060408385031215610ab957600080fd5b610ac283610a8d565b946020939093013593505050565b60008060008060608587031215610ae657600080fd5b610aef85610a8d565b935060208501359250604085013567ffffffffffffffff80821115610b1357600080fd5b818701915087601f830112610b2757600080fd5b813581811115610b3657600080fd5b886020828501011115610b4857600080fd5b95989497505060200194505050565b600060208284031215610b6957600080fd5b6104c982610a8d565b73ffffffffffffffffffffffffffffffffffffffff81168114610b9457600080fd5b50565b600080600060608486031215610bac57600080fd5b83359250602084013591506040840135610bc581610b72565b809150509250925092565b60005b83811015610beb578181015183820152602001610bd3565b50506000910152565b60008151808452610c0c816020860160208601610bd0565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b6020815260006104c96020830184610bf4565b600060208284031215610c6357600080fd5b81356104c981610b72565b600080600080600060a08688031215610c8657600080fd5b85359450610c9660208701610a8d565b9350604086013592506060860135610cad81610b72565b949793965091946080013592915050565b600080600060608486031215610cd357600080fd5b505081359360208301359350604090920135919050565b600060208284031215610cfc57600080fd5b81516104c981610b72565b63ffffffff85168152836020820152826040820152608060608201526000610d326080830184610bf4565b9695505050505050565b600060208284031215610d4e57600080fd5b815167ffffffffffffffff811681146104c957600080fd5b600060208284031215610d7857600080fd5b815180151581146104c957600080fd5b60008251610d9a818460208701610bd0565b919091019291505056fea2646970667358221220ae13fad0038e3868851a210cae376ad28580b982b8441938ff8d42a9df74fde064736f6c63430008110033","runtime-code":"0x608060405234801561001057600080fd5b50600436106100885760003560e01c8063b6aa3fe31161005b578063b6aa3fe314610151578063cb75c11c14610171578063f5af2a4514610191578063f856ddb6146101e657600080fd5b80632c1219211461008d5780636b51d203146100d757806396abeb7014610100578063b35b046414610123575b600080fd5b6000546100ad9073ffffffffffffffffffffffffffffffffffffffff1681565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b6100fe6100e5366004610aa6565b63ffffffff909116600090815260026020526040902055565b005b61011361010e366004610ad0565b610212565b60405190151581526020016100ce565b610143610131366004610b57565b60026020526000908152604090205481565b6040519081526020016100ce565b61016461015f366004610b97565b610482565b6040516100ce9190610c3e565b6001546100ad9073ffffffffffffffffffffffffffffffffffffffff1681565b6100fe61019f366004610c51565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055565b6101f96101f4366004610c6e565b6104d0565b60405167ffffffffffffffff90911681526020016100ce565b6000805473ffffffffffffffffffffffffffffffffffffffff163314610299576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f496e76616c6964206d657373616765207472616e736d6974746572000000000060448201526064015b60405180910390fd5b63ffffffff8516600090815260026020526040902054841461033d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602160248201527f52656d6f746520546f6b656e4d657373656e67657220756e737570706f72746560448201527f64000000000000000000000000000000000000000000000000000000000000006064820152608401610290565b6000808061034d85870187610cbe565b6001546040517fd54de06f00000000000000000000000000000000000000000000000000000000815263ffffffff8d1660048201526024810183905273ffffffffffffffffffffffffffffffffffffffff808516604483015260648201869052949750929550909350600092169063d54de06f906084016020604051808303816000875af11580156103e3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104079190610cea565b90508073ffffffffffffffffffffffffffffffffffffffff168360001c73ffffffffffffffffffffffffffffffffffffffff167f1b2a7ff080b8cb6ff436ce0372e399692bbfb6d4ae5766fd8d58a7b8cc6142e68660405161046b91815260200190565b60405180910390a350600198975050505050505050565b604080516020810185905290810183905273ffffffffffffffffffffffffffffffffffffffff82166060808301919091529060800160405160208183030381529060405290505b9392505050565b6001546000906104fc9073ffffffffffffffffffffffffffffffffffffffff85811691339116896106e1565b6001546040517f9dc29fac00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff85811660048301526024820189905290911690639dc29fac90604401600060405180830381600087803b15801561057057600080fd5b505af1158015610584573d6000803e3d6000fd5b505050506000610595878686610482565b6000805463ffffffff8916825260026020526040918290205491517ff7259a7500000000000000000000000000000000000000000000000000000000815292935073ffffffffffffffffffffffffffffffffffffffff169163f7259a7591610606918a919088908790600401610d07565b6020604051808303816000875af1158015610625573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106499190610d3c565b63ffffffff87166000818152600260209081526040918290205482518c81529182018a905291810192909252606082015260808101859052909250339073ffffffffffffffffffffffffffffffffffffffff86169067ffffffffffffffff8516907f2fa9ca894982930190727e75500a97d8dc500233a5065e0f3126c48fbe0343c09060a00160405180910390a45095945050505050565b6040805173ffffffffffffffffffffffffffffffffffffffff85811660248301528416604482015260648082018490528251808303909101815260849091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f23b872dd0000000000000000000000000000000000000000000000000000000017905261077690859061077c565b50505050565b60006107de826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff1661088d9092919063ffffffff16565b80519091501561088857808060200190518101906107fc9190610d66565b610888576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f742073756363656564000000000000000000000000000000000000000000006064820152608401610290565b505050565b606061089c84846000856108a4565b949350505050565b606082471015610936576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c00000000000000000000000000000000000000000000000000006064820152608401610290565b73ffffffffffffffffffffffffffffffffffffffff85163b6109b4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610290565b6000808673ffffffffffffffffffffffffffffffffffffffff1685876040516109dd9190610d88565b60006040518083038185875af1925050503d8060008114610a1a576040519150601f19603f3d011682016040523d82523d6000602084013e610a1f565b606091505b5091509150610a2f828286610a3a565b979650505050505050565b60608315610a495750816104c9565b825115610a595782518084602001fd5b816040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016102909190610c3e565b803563ffffffff81168114610aa157600080fd5b919050565b60008060408385031215610ab957600080fd5b610ac283610a8d565b946020939093013593505050565b60008060008060608587031215610ae657600080fd5b610aef85610a8d565b935060208501359250604085013567ffffffffffffffff80821115610b1357600080fd5b818701915087601f830112610b2757600080fd5b813581811115610b3657600080fd5b886020828501011115610b4857600080fd5b95989497505060200194505050565b600060208284031215610b6957600080fd5b6104c982610a8d565b73ffffffffffffffffffffffffffffffffffffffff81168114610b9457600080fd5b50565b600080600060608486031215610bac57600080fd5b83359250602084013591506040840135610bc581610b72565b809150509250925092565b60005b83811015610beb578181015183820152602001610bd3565b50506000910152565b60008151808452610c0c816020860160208601610bd0565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b6020815260006104c96020830184610bf4565b600060208284031215610c6357600080fd5b81356104c981610b72565b600080600080600060a08688031215610c8657600080fd5b85359450610c9660208701610a8d565b9350604086013592506060860135610cad81610b72565b949793965091946080013592915050565b600080600060608486031215610cd357600080fd5b505081359360208301359350604090920135919050565b600060208284031215610cfc57600080fd5b81516104c981610b72565b63ffffffff85168152836020820152826040820152608060608201526000610d326080830184610bf4565b9695505050505050565b600060208284031215610d4e57600080fd5b815167ffffffffffffffff811681146104c957600080fd5b600060208284031215610d7857600080fd5b815180151581146104c957600080fd5b60008251610d9a818460208701610bd0565b919091019291505056fea2646970667358221220ae13fad0038e3868851a210cae376ad28580b982b8441938ff8d42a9df74fde064736f6c63430008110033","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity 0.8.17;\n\nabstract contract TokenMessengerEvents {\n /**\n * @notice Emitted when a DepositForBurn message is sent\n * @param nonce unique nonce reserved by message\n * @param burnToken address of token burnt on source domain\n * @param amount deposit amount\n * @param depositor address where deposit is transferred from\n * @param mintRecipient address receiving minted tokens on destination domain as bytes32\n * @param destinationDomain destination domain\n * @param destinationTokenMessenger address of TokenMessenger on destination domain as bytes32\n * @param destinationCaller authorized caller as bytes32 of receiveMessage() on destination domain, if not equal to bytes32(0).\n * If equal to bytes32(0), any address can call receiveMessage().\n */\n event DepositForBurn(\n uint64 indexed nonce,\n address indexed burnToken,\n uint256 amount,\n address indexed depositor,\n bytes32 mintRecipient,\n uint32 destinationDomain,\n bytes32 destinationTokenMessenger,\n bytes32 destinationCaller\n );\n\n /**\n * @notice Emitted when tokens are minted\n * @param mintRecipient recipient address of minted tokens\n * @param amount amount of minted tokens\n * @param mintToken contract address of minted token\n */\n event MintAndWithdraw(address indexed mintRecipient, uint256 amount, address indexed mintToken);\n}\n\ninterface IMessageTransmitter {\n /**\n * @notice Receives an incoming message, validating the header and passing\n * the body to application-specific handler.\n * @param message The message raw bytes\n * @param signature The message signature\n * @return success bool, true if successful\n */\n function receiveMessage(bytes calldata message, bytes calldata signature) external returns (bool success);\n\n /**\n * @notice Sends an outgoing message from the source domain, with a specified caller on the\n * destination domain.\n * @dev Increment nonce, format the message, and emit `MessageSent` event with message information.\n * WARNING: if the `destinationCaller` does not represent a valid address as bytes32, then it will not be possible\n * to broadcast the message on the destination domain. This is an advanced feature, and the standard\n * sendMessage() should be preferred for use cases where a specific destination caller is not required.\n * @param destinationDomain Domain of destination chain\n * @param recipient Address of message recipient on destination domain as bytes32\n * @param destinationCaller caller on the destination domain, as bytes32\n * @param messageBody Raw bytes content of message\n * @return nonce reserved by message\n */\n function sendMessageWithCaller(\n uint32 destinationDomain,\n bytes32 recipient,\n bytes32 destinationCaller,\n bytes calldata messageBody\n ) external returns (uint64);\n\n // ═══════════════════════════════════════════════════ VIEWS ═══════════════════════════════════════════════════════\n\n // Domain of chain on which the contract is deployed\n function localDomain() external view returns (uint32);\n\n // Next available nonce from this source domain\n function nextAvailableNonce() external view returns (uint64);\n}\n\ninterface ITokenMessenger {\n /**\n * @notice Deposits and burns tokens from sender to be minted on destination domain. The mint\n * on the destination domain must be called by `destinationCaller`.\n * WARNING: if the `destinationCaller` does not represent a valid address as bytes32, then it will not be possible\n * to broadcast the message on the destination domain. This is an advanced feature, and the standard\n * depositForBurn() should be preferred for use cases where a specific destination caller is not required.\n * Emits a `DepositForBurn` event.\n * @dev reverts if:\n * - given destinationCaller is zero address\n * - given burnToken is not supported\n * - given destinationDomain has no TokenMessenger registered\n * - transferFrom() reverts. For example, if sender's burnToken balance or approved allowance\n * to this contract is less than `amount`.\n * - burn() reverts. For example, if `amount` is 0.\n * - MessageTransmitter returns false or reverts.\n * @param amount amount of tokens to burn\n * @param destinationDomain destination domain\n * @param mintRecipient address of mint recipient on destination domain\n * @param burnToken address of contract to burn deposited tokens, on local domain\n * @param destinationCaller caller on the destination domain, as bytes32\n * @return nonce unique nonce reserved by message\n */\n function depositForBurnWithCaller(\n uint256 amount,\n uint32 destinationDomain,\n bytes32 mintRecipient,\n address burnToken,\n bytes32 destinationCaller\n ) external returns (uint64 nonce);\n\n /**\n * @notice Handles an incoming message received by the local MessageTransmitter,\n * and takes the appropriate action. For a burn message, mints the\n * associated token to the requested recipient on the local domain.\n * @dev Validates the local sender is the local MessageTransmitter, and the\n * remote sender is a registered remote TokenMessenger for `remoteDomain`.\n * @param remoteDomain The domain where the message originated from.\n * @param sender The sender of the message (remote TokenMessenger).\n * @param messageBody The message body bytes.\n * @return success Bool, true if successful.\n */\n function handleReceiveMessage(\n uint32 remoteDomain,\n bytes32 sender,\n bytes calldata messageBody\n ) external returns (bool success);\n\n // ═══════════════════════════════════════════════════ VIEWS ═══════════════════════════════════════════════════════\n\n // Local Message Transmitter responsible for sending and receiving messages to/from remote domains\n function localMessageTransmitter() external view returns (address);\n\n // Minter responsible for minting and burning tokens on the local domain\n function localMinter() external view returns (address);\n}\n\ninterface ITokenMinter {\n /**\n * @notice Mints `amount` of local tokens corresponding to the\n * given (`sourceDomain`, `burnToken`) pair, to `to` address.\n * @dev reverts if the (`sourceDomain`, `burnToken`) pair does not\n * map to a nonzero local token address. This mapping can be queried using\n * getLocalToken().\n * @param sourceDomain Source domain where `burnToken` was burned.\n * @param burnToken Burned token address as bytes32.\n * @param to Address to receive minted tokens, corresponding to `burnToken`,\n * on this domain.\n * @param amount Amount of tokens to mint. Must be less than or equal\n * to the minterAllowance of this TokenMinter for given `_mintToken`.\n * @return mintToken token minted.\n */\n function mint(\n uint32 sourceDomain,\n bytes32 burnToken,\n address to,\n uint256 amount\n ) external returns (address mintToken);\n\n /**\n * @notice Burn tokens owned by this ITokenMinter.\n * @param burnToken burnable token.\n * @param amount amount of tokens to burn. Must be less than or equal to this ITokenMinter's\n * account balance of the given `_burnToken`.\n */\n function burn(address burnToken, uint256 amount) external;\n\n /**\n * @notice Get the local token associated with the given remote domain and token.\n * @param remoteDomain Remote domain\n * @param remoteToken Remote token\n * @return local token address\n */\n function getLocalToken(uint32 remoteDomain, bytes32 remoteToken) external view returns (address);\n\n // local token (address) =\u003e maximum burn amounts per message\n function burnLimitsPerMessage(address token) external view returns (uint256);\n}\n\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/utils/SafeERC20.sol)\n\n// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\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(\n address from,\n address to,\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\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\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 * [IMPORTANT]\n * ====\n * You shouldn't rely on `isContract` to protect against flash loan attacks!\n *\n * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\n * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\n * constructor.\n * ====\n */\n function isContract(address account) internal view returns (bool) {\n // This method relies on extcodesize/address.code.length, which returns 0\n // for contracts in construction, since the code is only stored at the end\n // of the constructor execution.\n\n return account.code.length \u003e 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 \u003e= amount, \"Address: insufficient balance\");\n\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(\n address target,\n bytes memory data,\n string memory errorMessage\n ) 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(\n address target,\n bytes memory data,\n uint256 value\n ) 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(\n address target,\n bytes memory data,\n uint256 value,\n string memory errorMessage\n ) internal returns (bytes memory) {\n require(address(this).balance \u003e= value, \"Address: insufficient balance for call\");\n require(isContract(target), \"Address: call to non-contract\");\n\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(\n address target,\n bytes memory data,\n string memory errorMessage\n ) internal view returns (bytes memory) {\n require(isContract(target), \"Address: static call to non-contract\");\n\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResult(success, returndata, errorMessage);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n *\n * _Available since v3.4._\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionDelegateCall(target, data, \"Address: low-level delegate call failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n * but performing a delegate call.\n *\n * _Available since v3.4._\n */\n function functionDelegateCall(\n address target,\n bytes memory data,\n string memory errorMessage\n ) internal returns (bytes memory) {\n require(isContract(target), \"Address: delegate call to non-contract\");\n\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResult(success, returndata, errorMessage);\n }\n\n /**\n * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\n * revert reason using the provided one.\n *\n * _Available since v4.3._\n */\n function verifyCallResult(\n bool success,\n bytes memory returndata,\n string memory errorMessage\n ) internal 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 \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n\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\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n function safeTransfer(\n IERC20 token,\n address to,\n uint256 value\n ) internal {\n _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\n }\n\n function safeTransferFrom(\n IERC20 token,\n address from,\n address to,\n uint256 value\n ) internal {\n _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));\n }\n\n /**\n * @dev Deprecated. This function has issues similar to the ones found in\n * {IERC20-approve}, and its usage is discouraged.\n *\n * Whenever possible, use {safeIncreaseAllowance} and\n * {safeDecreaseAllowance} instead.\n */\n function safeApprove(\n IERC20 token,\n address spender,\n uint256 value\n ) internal {\n // safeApprove should only be called when setting an initial allowance,\n // or when resetting it to zero. To increase and decrease it, use\n // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\n require(\n (value == 0) || (token.allowance(address(this), spender) == 0),\n \"SafeERC20: approve from non-zero to non-zero allowance\"\n );\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\n }\n\n function safeIncreaseAllowance(\n IERC20 token,\n address spender,\n uint256 value\n ) internal {\n uint256 newAllowance = token.allowance(address(this), spender) + value;\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\n }\n\n function safeDecreaseAllowance(\n IERC20 token,\n address spender,\n uint256 value\n ) internal {\n unchecked {\n uint256 oldAllowance = token.allowance(address(this), spender);\n require(oldAllowance \u003e= value, \"SafeERC20: decreased allowance below zero\");\n uint256 newAllowance = oldAllowance - value;\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data, \"SafeERC20: low-level call failed\");\n if (returndata.length \u003e 0) {\n // Return data is optional\n require(abi.decode(returndata, (bool)), \"SafeERC20: ERC20 operation did not succeed\");\n }\n }\n}\n\ncontract MockTokenMessenger is TokenMessengerEvents, ITokenMessenger {\n using SafeERC20 for IERC20;\n\n address public override localMessageTransmitter;\n address public override localMinter;\n mapping(uint32 =\u003e bytes32) public remoteTokenMessenger;\n\n constructor(address localMessageTransmitter_) {\n localMessageTransmitter = localMessageTransmitter_;\n }\n\n function setLocalMinter(address localMinter_) external {\n localMinter = localMinter_;\n }\n\n function setRemoteTokenMessenger(uint32 remoteDomain, bytes32 remoteTokenMessenger_) external {\n remoteTokenMessenger[remoteDomain] = remoteTokenMessenger_;\n }\n\n function depositForBurnWithCaller(\n uint256 amount,\n uint32 destinationDomain,\n bytes32 mintRecipient,\n address burnToken,\n bytes32 destinationCaller\n ) external returns (uint64 nonce) {\n IERC20(burnToken).safeTransferFrom(msg.sender, localMinter, amount);\n ITokenMinter(localMinter).burn(burnToken, amount);\n bytes memory messageBody = formatTokenMessage(amount, mintRecipient, burnToken);\n nonce = IMessageTransmitter(localMessageTransmitter).sendMessageWithCaller(\n destinationDomain,\n remoteTokenMessenger[destinationDomain],\n destinationCaller,\n messageBody\n );\n emit DepositForBurn({\n nonce: nonce,\n burnToken: burnToken,\n amount: amount,\n depositor: msg.sender,\n mintRecipient: mintRecipient,\n destinationDomain: destinationDomain,\n destinationTokenMessenger: remoteTokenMessenger[destinationDomain],\n destinationCaller: destinationCaller\n });\n }\n\n function handleReceiveMessage(\n uint32 remoteDomain,\n bytes32 sender,\n bytes calldata messageBody\n ) external returns (bool success) {\n require(msg.sender == localMessageTransmitter, \"Invalid message transmitter\");\n require(sender == remoteTokenMessenger[remoteDomain], \"Remote TokenMessenger unsupported\");\n (uint256 amount, bytes32 mintRecipient, bytes32 burnToken) = abi.decode(\n messageBody,\n (uint256, bytes32, bytes32)\n );\n address mintToken = ITokenMinter(localMinter).mint(\n remoteDomain,\n burnToken,\n address(uint160(uint256(mintRecipient))),\n amount\n );\n emit MintAndWithdraw({\n mintRecipient: address(uint160(uint256(mintRecipient))),\n amount: amount,\n mintToken: mintToken\n });\n return true;\n }\n\n function formatTokenMessage(\n uint256 amount,\n bytes32 mintRecipient,\n address burnToken\n ) public pure returns (bytes memory tokenMessage) {\n return abi.encode(amount, mintRecipient, bytes32(uint256(uint160(burnToken))));\n }\n}\n","language":"Solidity","languageVersion":"0.8.17","compilerVersion":"0.8.17","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../","srcMap":"23097:2904:0:-:0;;;23360:113;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;23416:23;:50;;-1:-1:-1;;;;;;23416:50:0;-1:-1:-1;;;;;23416:50:0;;;;;;;;;;23097:2904;;14:290:1;84:6;137:2;125:9;116:7;112:23;108:32;105:52;;;153:1;150;143:12;105:52;179:16;;-1:-1:-1;;;;;224:31:1;;214:42;;204:70;;270:1;267;260:12;204:70;293:5;14:290;-1:-1:-1;;;14:290:1:o;:::-;23097:2904:0;;;;;;","srcMapRuntime":"23097:2904:0:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;23205:47;;;;;;;;;;;;190:42:1;178:55;;;160:74;;148:2;133:18;23205:47:0;;;;;;;;23583:169;;;;;;:::i;:::-;23687:34;;;;;;;;:20;:34;;;;;:58;23583:169;;;24839:895;;;;;;:::i;:::-;;:::i;:::-;;;1571:14:1;;1564:22;1546:41;;1534:2;1519:18;24839:895:0;1406:187:1;23299:54:0;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;1933:25:1;;;1921:2;1906:18;23299:54:0;1787:177:1;25740:259:0;;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;23258:35::-;;;;;;;;;23479:98;;;;;;:::i;:::-;23544:11;:26;;;;;;;;;;;;;;;23479:98;23758:1075;;;;;;:::i;:::-;;:::i;:::-;;;4283:18:1;4271:31;;;4253:50;;4241:2;4226:18;23758:1075:0;4109:200:1;24839:895:0;24982:12;25028:23;;;;25014:10;:37;25006:77;;;;;;;4516:2:1;25006:77:0;;;4498:21:1;4555:2;4535:18;;;4528:30;4594:29;4574:18;;;4567:57;4641:18;;25006:77:0;;;;;;;;;25111:34;;;;;;;:20;:34;;;;;;25101:44;;25093:90;;;;;;;4872:2:1;25093:90:0;;;4854:21:1;4911:2;4891:18;;;4884:30;4950:34;4930:18;;;4923:62;5021:3;5001:18;;;4994:31;5042:19;;25093:90:0;4670:397:1;25093:90:0;25194:14;;;25254:86;;;;25278:11;25254:86;:::i;:::-;25383:11;;25370:163;;;;;5652:10:1;5640:23;;25370:163:0;;;5622:42:1;5680:18;;;5673:34;;;25383:11:0;5743:55:1;;;5723:18;;;5716:83;5815:18;;;5808:34;;;25193:147:0;;-1:-1:-1;25193:147:0;;-1:-1:-1;25193:147:0;;-1:-1:-1;25350:17:0;;25383:11;;25370:30;;5594:19:1;;25370:163:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;25350:183;;25686:9;25548:158;;25617:13;25609:22;;25548:158;;;25655:6;25548:158;;;;1933:25:1;;1921:2;1906:18;;1787:177;25548:158:0;;;;;;;;-1:-1:-1;25723:4:0;;24839:895;-1:-1:-1;;;;;;;;24839:895:0:o;25740:259::-;25921:71;;;;;;6493:25:1;;;6534:18;;;6527:34;;;25963:27:0;;;25877:25;6577:18:1;;;6570:34;;;;25877:25:0;6466:18:1;;25921:71:0;;;;;;;;;;;;25914:78;;25740:259;;;;;;:::o;23758:1075::-;24038:11;;23967:12;;23991:67;;24038:11;23991:34;;;;24026:10;;24038:11;24051:6;23991:34;:67::i;:::-;24081:11;;24068:49;;;;;24081:11;6807:55:1;;;24068:49:0;;;6789:74:1;6879:18;;;6872:34;;;24081:11:0;;;;24068:30;;6762:18:1;;24068:49:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;24127:24;24154:52;24173:6;24181:13;24196:9;24154:18;:52::i;:::-;24244:23;;;24335:39;;;;;:20;:39;;;;;;;;24224:216;;;;;24127:79;;-1:-1:-1;24244:23:0;;;24224:66;;:216;;24304:17;;24335:39;24388:17;;24127:79;;24224:216;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;24726:39;;;;;;;:20;:39;;;;;;;;;;24455:371;;7919:25:1;;;7960:18;;;7953:34;;;8003:18;;;7996:51;;;;8078:2;8063:18;;8056:34;8121:3;8106:19;;8099:35;;;24216:224:0;;-1:-1:-1;24583:10:0;;24455:371;;;;;;;;;;7906:3:1;7891:19;24455:371:0;;;;;;;23981:852;23758:1075;;;;;;;:::o;20092:241::-;20257:68;;;8357:42:1;8426:15;;;20257:68:0;;;8408:34:1;8478:15;;8458:18;;;8451:43;8510:18;;;;8503:34;;;20257:68:0;;;;;;;;;;8320:18:1;;;;20257:68:0;;;;;;;;;;20280:27;20257:68;;;20230:96;;20250:5;;20230:19;:96::i;:::-;20092:241;;;;:::o;22387:706::-;22806:23;22832:69;22860:4;22832:69;;;;;;;;;;;;;;;;;22840:5;22832:27;;;;:69;;;;;:::i;:::-;22915:17;;22806:95;;-1:-1:-1;22915:21:0;22911:176;;23010:10;22999:30;;;;;;;;;;;;:::i;:::-;22991:85;;;;;;;9032:2:1;22991:85:0;;;9014:21:1;9071:2;9051:18;;;9044:30;9110:34;9090:18;;;9083:62;9181:12;9161:18;;;9154:40;9211:19;;22991:85:0;8830:406:1;22991:85:0;22457:636;22387:706;;:::o;14971:223::-;15104:12;15135:52;15157:6;15165:4;15171:1;15174:12;15135:21;:52::i;:::-;15128:59;14971:223;-1:-1:-1;;;;14971:223:0:o;16058:499::-;16223:12;16280:5;16255:21;:30;;16247:81;;;;;;;9443:2:1;16247:81:0;;;9425:21:1;9482:2;9462:18;;;9455:30;9521:34;9501:18;;;9494:62;9592:8;9572:18;;;9565:36;9618:19;;16247:81:0;9241:402:1;16247:81:0;12575:19;;;;16338:60;;;;;;;9850:2:1;16338:60:0;;;9832:21:1;9889:2;9869:18;;;9862:30;9928:31;9908:18;;;9901:59;9977:18;;16338:60:0;9648:353:1;16338:60:0;16410:12;16424:23;16451:6;:11;;16470:5;16477:4;16451:31;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;16409:73;;;;16499:51;16516:7;16525:10;16537:12;16499:16;:51::i;:::-;16492:58;16058:499;-1:-1:-1;;;;;;;16058:499:0:o;18671:692::-;18817:12;18845:7;18841:516;;;-1:-1:-1;18875:10:0;18868:17;;18841:516;18986:17;;:21;18982:365;;19180:10;19174:17;19240:15;19227:10;19223:2;19219:19;19212:44;18982:365;19319:12;19312:20;;;;;;;;;;;:::i;245:163:1:-;312:20;;372:10;361:22;;351:33;;341:61;;398:1;395;388:12;341:61;245:163;;;:::o;413:252::-;480:6;488;541:2;529:9;520:7;516:23;512:32;509:52;;;557:1;554;547:12;509:52;580:28;598:9;580:28;:::i;:::-;570:38;655:2;640:18;;;;627:32;;-1:-1:-1;;;413:252:1:o;670:731::-;757:6;765;773;781;834:2;822:9;813:7;809:23;805:32;802:52;;;850:1;847;840:12;802:52;873:28;891:9;873:28;:::i;:::-;863:38;;948:2;937:9;933:18;920:32;910:42;;1003:2;992:9;988:18;975:32;1026:18;1067:2;1059:6;1056:14;1053:34;;;1083:1;1080;1073:12;1053:34;1121:6;1110:9;1106:22;1096:32;;1166:7;1159:4;1155:2;1151:13;1147:27;1137:55;;1188:1;1185;1178:12;1137:55;1228:2;1215:16;1254:2;1246:6;1243:14;1240:34;;;1270:1;1267;1260:12;1240:34;1315:7;1310:2;1301:6;1297:2;1293:15;1289:24;1286:37;1283:57;;;1336:1;1333;1326:12;1283:57;670:731;;;;-1:-1:-1;;1367:2:1;1359:11;;-1:-1:-1;;;670:731:1:o;1598:184::-;1656:6;1709:2;1697:9;1688:7;1684:23;1680:32;1677:52;;;1725:1;1722;1715:12;1677:52;1748:28;1766:9;1748:28;:::i;1969:154::-;2055:42;2048:5;2044:54;2037:5;2034:65;2024:93;;2113:1;2110;2103:12;2024:93;1969:154;:::o;2128:383::-;2205:6;2213;2221;2274:2;2262:9;2253:7;2249:23;2245:32;2242:52;;;2290:1;2287;2280:12;2242:52;2326:9;2313:23;2303:33;;2383:2;2372:9;2368:18;2355:32;2345:42;;2437:2;2426:9;2422:18;2409:32;2450:31;2475:5;2450:31;:::i;:::-;2500:5;2490:15;;;2128:383;;;;;:::o;2516:250::-;2601:1;2611:113;2625:6;2622:1;2619:13;2611:113;;;2701:11;;;2695:18;2682:11;;;2675:39;2647:2;2640:10;2611:113;;;-1:-1:-1;;2758:1:1;2740:16;;2733:27;2516:250::o;2771:329::-;2812:3;2850:5;2844:12;2877:6;2872:3;2865:19;2893:76;2962:6;2955:4;2950:3;2946:14;2939:4;2932:5;2928:16;2893:76;:::i;:::-;3014:2;3002:15;3019:66;2998:88;2989:98;;;;3089:4;2985:109;;2771:329;-1:-1:-1;;2771:329:1:o;3105:217::-;3252:2;3241:9;3234:21;3215:4;3272:44;3312:2;3301:9;3297:18;3289:6;3272:44;:::i;3327:247::-;3386:6;3439:2;3427:9;3418:7;3414:23;3410:32;3407:52;;;3455:1;3452;3445:12;3407:52;3494:9;3481:23;3513:31;3538:5;3513:31;:::i;3579:525::-;3673:6;3681;3689;3697;3705;3758:3;3746:9;3737:7;3733:23;3729:33;3726:53;;;3775:1;3772;3765:12;3726:53;3811:9;3798:23;3788:33;;3840:37;3873:2;3862:9;3858:18;3840:37;:::i;:::-;3830:47;;3924:2;3913:9;3909:18;3896:32;3886:42;;3978:2;3967:9;3963:18;3950:32;3991:31;4016:5;3991:31;:::i;:::-;3579:525;;;;-1:-1:-1;3579:525:1;;4093:3;4078:19;4065:33;;3579:525;-1:-1:-1;;3579:525:1:o;5072:316::-;5149:6;5157;5165;5218:2;5206:9;5197:7;5193:23;5189:32;5186:52;;;5234:1;5231;5224:12;5186:52;-1:-1:-1;;5257:23:1;;;5327:2;5312:18;;5299:32;;-1:-1:-1;5378:2:1;5363:18;;;5350:32;;5072:316;-1:-1:-1;5072:316:1:o;5853:251::-;5923:6;5976:2;5964:9;5955:7;5951:23;5947:32;5944:52;;;5992:1;5989;5982:12;5944:52;6024:9;6018:16;6043:31;6068:5;6043:31;:::i;6917:447::-;7158:10;7150:6;7146:23;7135:9;7128:42;7206:6;7201:2;7190:9;7186:18;7179:34;7249:6;7244:2;7233:9;7229:18;7222:34;7292:3;7287:2;7276:9;7272:18;7265:31;7109:4;7313:45;7353:3;7342:9;7338:19;7330:6;7313:45;:::i;:::-;7305:53;6917:447;-1:-1:-1;;;;;;6917:447:1:o;7369:288::-;7438:6;7491:2;7479:9;7470:7;7466:23;7462:32;7459:52;;;7507:1;7504;7497:12;7459:52;7539:9;7533:16;7589:18;7582:5;7578:30;7571:5;7568:41;7558:69;;7623:1;7620;7613:12;8548:277;8615:6;8668:2;8656:9;8647:7;8643:23;8639:32;8636:52;;;8684:1;8681;8674:12;8636:52;8716:9;8710:16;8769:5;8762:13;8755:21;8748:5;8745:32;8735:60;;8791:1;8788;8781:12;10006:287;10135:3;10173:6;10167:13;10189:66;10248:6;10243:3;10236:4;10228:6;10224:17;10189:66;:::i;:::-;10271:16;;;;;10006:287;-1:-1:-1;;10006:287:1:o","abiDefinition":[{"inputs":[{"internalType":"address","name":"localMessageTransmitter_","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint64","name":"nonce","type":"uint64"},{"indexed":true,"internalType":"address","name":"burnToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":true,"internalType":"address","name":"depositor","type":"address"},{"indexed":false,"internalType":"bytes32","name":"mintRecipient","type":"bytes32"},{"indexed":false,"internalType":"uint32","name":"destinationDomain","type":"uint32"},{"indexed":false,"internalType":"bytes32","name":"destinationTokenMessenger","type":"bytes32"},{"indexed":false,"internalType":"bytes32","name":"destinationCaller","type":"bytes32"}],"name":"DepositForBurn","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"mintRecipient","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":true,"internalType":"address","name":"mintToken","type":"address"}],"name":"MintAndWithdraw","type":"event"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint32","name":"destinationDomain","type":"uint32"},{"internalType":"bytes32","name":"mintRecipient","type":"bytes32"},{"internalType":"address","name":"burnToken","type":"address"},{"internalType":"bytes32","name":"destinationCaller","type":"bytes32"}],"name":"depositForBurnWithCaller","outputs":[{"internalType":"uint64","name":"nonce","type":"uint64"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"bytes32","name":"mintRecipient","type":"bytes32"},{"internalType":"address","name":"burnToken","type":"address"}],"name":"formatTokenMessage","outputs":[{"internalType":"bytes","name":"tokenMessage","type":"bytes"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint32","name":"remoteDomain","type":"uint32"},{"internalType":"bytes32","name":"sender","type":"bytes32"},{"internalType":"bytes","name":"messageBody","type":"bytes"}],"name":"handleReceiveMessage","outputs":[{"internalType":"bool","name":"success","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"localMessageTransmitter","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"localMinter","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint32","name":"","type":"uint32"}],"name":"remoteTokenMessenger","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"localMinter_","type":"address"}],"name":"setLocalMinter","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint32","name":"remoteDomain","type":"uint32"},{"internalType":"bytes32","name":"remoteTokenMessenger_","type":"bytes32"}],"name":"setRemoteTokenMessenger","outputs":[],"stateMutability":"nonpayable","type":"function"}],"userDoc":{"events":{"DepositForBurn(uint64,address,uint256,address,bytes32,uint32,bytes32,bytes32)":{"notice":"Emitted when a DepositForBurn message is sent"},"MintAndWithdraw(address,uint256,address)":{"notice":"Emitted when tokens are minted"}},"kind":"user","methods":{"depositForBurnWithCaller(uint256,uint32,bytes32,address,bytes32)":{"notice":"Deposits and burns tokens from sender to be minted on destination domain. The mint on the destination domain must be called by `destinationCaller`. WARNING: if the `destinationCaller` does not represent a valid address as bytes32, then it will not be possible to broadcast the message on the destination domain. This is an advanced feature, and the standard depositForBurn() should be preferred for use cases where a specific destination caller is not required. Emits a `DepositForBurn` event."},"handleReceiveMessage(uint32,bytes32,bytes)":{"notice":"Handles an incoming message received by the local MessageTransmitter, and takes the appropriate action. For a burn message, mints the associated token to the requested recipient on the local domain."}},"version":1},"developerDoc":{"kind":"dev","methods":{"depositForBurnWithCaller(uint256,uint32,bytes32,address,bytes32)":{"details":"reverts if: - given destinationCaller is zero address - given burnToken is not supported - given destinationDomain has no TokenMessenger registered - transferFrom() reverts. For example, if sender's burnToken balance or approved allowance to this contract is less than `amount`. - burn() reverts. For example, if `amount` is 0. - MessageTransmitter returns false or reverts.","params":{"amount":"amount of tokens to burn","burnToken":"address of contract to burn deposited tokens, on local domain","destinationCaller":"caller on the destination domain, as bytes32","destinationDomain":"destination domain","mintRecipient":"address of mint recipient on destination domain"},"returns":{"nonce":"unique nonce reserved by message"}},"handleReceiveMessage(uint32,bytes32,bytes)":{"details":"Validates the local sender is the local MessageTransmitter, and the remote sender is a registered remote TokenMessenger for `remoteDomain`.","params":{"messageBody":"The message body bytes.","remoteDomain":"The domain where the message originated from.","sender":"The sender of the message (remote TokenMessenger)."},"returns":{"success":"Bool, true if successful."}}},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.17+commit.8df45f5f\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"localMessageTransmitter_\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint64\",\"name\":\"nonce\",\"type\":\"uint64\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"burnToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"mintRecipient\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"destinationDomain\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"destinationTokenMessenger\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"destinationCaller\",\"type\":\"bytes32\"}],\"name\":\"DepositForBurn\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"mintRecipient\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"mintToken\",\"type\":\"address\"}],\"name\":\"MintAndWithdraw\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint32\",\"name\":\"destinationDomain\",\"type\":\"uint32\"},{\"internalType\":\"bytes32\",\"name\":\"mintRecipient\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"burnToken\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"destinationCaller\",\"type\":\"bytes32\"}],\"name\":\"depositForBurnWithCaller\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"nonce\",\"type\":\"uint64\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"bytes32\",\"name\":\"mintRecipient\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"burnToken\",\"type\":\"address\"}],\"name\":\"formatTokenMessage\",\"outputs\":[{\"internalType\":\"bytes\",\"name\":\"tokenMessage\",\"type\":\"bytes\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"remoteDomain\",\"type\":\"uint32\"},{\"internalType\":\"bytes32\",\"name\":\"sender\",\"type\":\"bytes32\"},{\"internalType\":\"bytes\",\"name\":\"messageBody\",\"type\":\"bytes\"}],\"name\":\"handleReceiveMessage\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"success\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"localMessageTransmitter\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"localMinter\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"name\":\"remoteTokenMessenger\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"localMinter_\",\"type\":\"address\"}],\"name\":\"setLocalMinter\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"remoteDomain\",\"type\":\"uint32\"},{\"internalType\":\"bytes32\",\"name\":\"remoteTokenMessenger_\",\"type\":\"bytes32\"}],\"name\":\"setRemoteTokenMessenger\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{\"depositForBurnWithCaller(uint256,uint32,bytes32,address,bytes32)\":{\"details\":\"reverts if: - given destinationCaller is zero address - given burnToken is not supported - given destinationDomain has no TokenMessenger registered - transferFrom() reverts. For example, if sender's burnToken balance or approved allowance to this contract is less than `amount`. - burn() reverts. For example, if `amount` is 0. - MessageTransmitter returns false or reverts.\",\"params\":{\"amount\":\"amount of tokens to burn\",\"burnToken\":\"address of contract to burn deposited tokens, on local domain\",\"destinationCaller\":\"caller on the destination domain, as bytes32\",\"destinationDomain\":\"destination domain\",\"mintRecipient\":\"address of mint recipient on destination domain\"},\"returns\":{\"nonce\":\"unique nonce reserved by message\"}},\"handleReceiveMessage(uint32,bytes32,bytes)\":{\"details\":\"Validates the local sender is the local MessageTransmitter, and the remote sender is a registered remote TokenMessenger for `remoteDomain`.\",\"params\":{\"messageBody\":\"The message body bytes.\",\"remoteDomain\":\"The domain where the message originated from.\",\"sender\":\"The sender of the message (remote TokenMessenger).\"},\"returns\":{\"success\":\"Bool, true if successful.\"}}},\"version\":1},\"userdoc\":{\"events\":{\"DepositForBurn(uint64,address,uint256,address,bytes32,uint32,bytes32,bytes32)\":{\"notice\":\"Emitted when a DepositForBurn message is sent\"},\"MintAndWithdraw(address,uint256,address)\":{\"notice\":\"Emitted when tokens are minted\"}},\"kind\":\"user\",\"methods\":{\"depositForBurnWithCaller(uint256,uint32,bytes32,address,bytes32)\":{\"notice\":\"Deposits and burns tokens from sender to be minted on destination domain. The mint on the destination domain must be called by `destinationCaller`. WARNING: if the `destinationCaller` does not represent a valid address as bytes32, then it will not be possible to broadcast the message on the destination domain. This is an advanced feature, and the standard depositForBurn() should be preferred for use cases where a specific destination caller is not required. Emits a `DepositForBurn` event.\"},\"handleReceiveMessage(uint32,bytes32,bytes)\":{\"notice\":\"Handles an incoming message received by the local MessageTransmitter, and takes the appropriate action. For a burn message, mints the associated token to the requested recipient on the local domain.\"}},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/MockTokenMessenger.sol\":\"MockTokenMessenger\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/MockTokenMessenger.sol\":{\"keccak256\":\"0x676112f99e502493a5f5dddf4043b92d8baf8accb1bdc704a0e77529ddba46d6\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://b7f4c1c133460718570f7c97bf1f098cc47625b54e419be0bc87dcbc1863e3ce\",\"dweb:/ipfs/QmdAEfnnzhMPUcAaAGnG9zeY8KPpnLrR9PKx4VMSqb6Usx\"]}},\"version\":1}"},"hashes":{"depositForBurnWithCaller(uint256,uint32,bytes32,address,bytes32)":"f856ddb6","formatTokenMessage(uint256,bytes32,address)":"b6aa3fe3","handleReceiveMessage(uint32,bytes32,bytes)":"96abeb70","localMessageTransmitter()":"2c121921","localMinter()":"cb75c11c","remoteTokenMessenger(uint32)":"b35b0464","setLocalMinter(address)":"f5af2a45","setRemoteTokenMessenger(uint32,bytes32)":"6b51d203"}},"solidity/MockTokenMessenger.sol:SafeERC20":{"code":"0x60566037600b82828239805160001a607314602a57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600080fdfea2646970667358221220e451fbb2ae2021d046e31729b8bbb8de266bb8126a0e9afcff2e64f68c67ab1b64736f6c63430008110033","runtime-code":"0x73000000000000000000000000000000000000000030146080604052600080fdfea2646970667358221220e451fbb2ae2021d046e31729b8bbb8de266bb8126a0e9afcff2e64f68c67ab1b64736f6c63430008110033","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity 0.8.17;\n\nabstract contract TokenMessengerEvents {\n /**\n * @notice Emitted when a DepositForBurn message is sent\n * @param nonce unique nonce reserved by message\n * @param burnToken address of token burnt on source domain\n * @param amount deposit amount\n * @param depositor address where deposit is transferred from\n * @param mintRecipient address receiving minted tokens on destination domain as bytes32\n * @param destinationDomain destination domain\n * @param destinationTokenMessenger address of TokenMessenger on destination domain as bytes32\n * @param destinationCaller authorized caller as bytes32 of receiveMessage() on destination domain, if not equal to bytes32(0).\n * If equal to bytes32(0), any address can call receiveMessage().\n */\n event DepositForBurn(\n uint64 indexed nonce,\n address indexed burnToken,\n uint256 amount,\n address indexed depositor,\n bytes32 mintRecipient,\n uint32 destinationDomain,\n bytes32 destinationTokenMessenger,\n bytes32 destinationCaller\n );\n\n /**\n * @notice Emitted when tokens are minted\n * @param mintRecipient recipient address of minted tokens\n * @param amount amount of minted tokens\n * @param mintToken contract address of minted token\n */\n event MintAndWithdraw(address indexed mintRecipient, uint256 amount, address indexed mintToken);\n}\n\ninterface IMessageTransmitter {\n /**\n * @notice Receives an incoming message, validating the header and passing\n * the body to application-specific handler.\n * @param message The message raw bytes\n * @param signature The message signature\n * @return success bool, true if successful\n */\n function receiveMessage(bytes calldata message, bytes calldata signature) external returns (bool success);\n\n /**\n * @notice Sends an outgoing message from the source domain, with a specified caller on the\n * destination domain.\n * @dev Increment nonce, format the message, and emit `MessageSent` event with message information.\n * WARNING: if the `destinationCaller` does not represent a valid address as bytes32, then it will not be possible\n * to broadcast the message on the destination domain. This is an advanced feature, and the standard\n * sendMessage() should be preferred for use cases where a specific destination caller is not required.\n * @param destinationDomain Domain of destination chain\n * @param recipient Address of message recipient on destination domain as bytes32\n * @param destinationCaller caller on the destination domain, as bytes32\n * @param messageBody Raw bytes content of message\n * @return nonce reserved by message\n */\n function sendMessageWithCaller(\n uint32 destinationDomain,\n bytes32 recipient,\n bytes32 destinationCaller,\n bytes calldata messageBody\n ) external returns (uint64);\n\n // ═══════════════════════════════════════════════════ VIEWS ═══════════════════════════════════════════════════════\n\n // Domain of chain on which the contract is deployed\n function localDomain() external view returns (uint32);\n\n // Next available nonce from this source domain\n function nextAvailableNonce() external view returns (uint64);\n}\n\ninterface ITokenMessenger {\n /**\n * @notice Deposits and burns tokens from sender to be minted on destination domain. The mint\n * on the destination domain must be called by `destinationCaller`.\n * WARNING: if the `destinationCaller` does not represent a valid address as bytes32, then it will not be possible\n * to broadcast the message on the destination domain. This is an advanced feature, and the standard\n * depositForBurn() should be preferred for use cases where a specific destination caller is not required.\n * Emits a `DepositForBurn` event.\n * @dev reverts if:\n * - given destinationCaller is zero address\n * - given burnToken is not supported\n * - given destinationDomain has no TokenMessenger registered\n * - transferFrom() reverts. For example, if sender's burnToken balance or approved allowance\n * to this contract is less than `amount`.\n * - burn() reverts. For example, if `amount` is 0.\n * - MessageTransmitter returns false or reverts.\n * @param amount amount of tokens to burn\n * @param destinationDomain destination domain\n * @param mintRecipient address of mint recipient on destination domain\n * @param burnToken address of contract to burn deposited tokens, on local domain\n * @param destinationCaller caller on the destination domain, as bytes32\n * @return nonce unique nonce reserved by message\n */\n function depositForBurnWithCaller(\n uint256 amount,\n uint32 destinationDomain,\n bytes32 mintRecipient,\n address burnToken,\n bytes32 destinationCaller\n ) external returns (uint64 nonce);\n\n /**\n * @notice Handles an incoming message received by the local MessageTransmitter,\n * and takes the appropriate action. For a burn message, mints the\n * associated token to the requested recipient on the local domain.\n * @dev Validates the local sender is the local MessageTransmitter, and the\n * remote sender is a registered remote TokenMessenger for `remoteDomain`.\n * @param remoteDomain The domain where the message originated from.\n * @param sender The sender of the message (remote TokenMessenger).\n * @param messageBody The message body bytes.\n * @return success Bool, true if successful.\n */\n function handleReceiveMessage(\n uint32 remoteDomain,\n bytes32 sender,\n bytes calldata messageBody\n ) external returns (bool success);\n\n // ═══════════════════════════════════════════════════ VIEWS ═══════════════════════════════════════════════════════\n\n // Local Message Transmitter responsible for sending and receiving messages to/from remote domains\n function localMessageTransmitter() external view returns (address);\n\n // Minter responsible for minting and burning tokens on the local domain\n function localMinter() external view returns (address);\n}\n\ninterface ITokenMinter {\n /**\n * @notice Mints `amount` of local tokens corresponding to the\n * given (`sourceDomain`, `burnToken`) pair, to `to` address.\n * @dev reverts if the (`sourceDomain`, `burnToken`) pair does not\n * map to a nonzero local token address. This mapping can be queried using\n * getLocalToken().\n * @param sourceDomain Source domain where `burnToken` was burned.\n * @param burnToken Burned token address as bytes32.\n * @param to Address to receive minted tokens, corresponding to `burnToken`,\n * on this domain.\n * @param amount Amount of tokens to mint. Must be less than or equal\n * to the minterAllowance of this TokenMinter for given `_mintToken`.\n * @return mintToken token minted.\n */\n function mint(\n uint32 sourceDomain,\n bytes32 burnToken,\n address to,\n uint256 amount\n ) external returns (address mintToken);\n\n /**\n * @notice Burn tokens owned by this ITokenMinter.\n * @param burnToken burnable token.\n * @param amount amount of tokens to burn. Must be less than or equal to this ITokenMinter's\n * account balance of the given `_burnToken`.\n */\n function burn(address burnToken, uint256 amount) external;\n\n /**\n * @notice Get the local token associated with the given remote domain and token.\n * @param remoteDomain Remote domain\n * @param remoteToken Remote token\n * @return local token address\n */\n function getLocalToken(uint32 remoteDomain, bytes32 remoteToken) external view returns (address);\n\n // local token (address) =\u003e maximum burn amounts per message\n function burnLimitsPerMessage(address token) external view returns (uint256);\n}\n\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/utils/SafeERC20.sol)\n\n// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\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(\n address from,\n address to,\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\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\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 * [IMPORTANT]\n * ====\n * You shouldn't rely on `isContract` to protect against flash loan attacks!\n *\n * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\n * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\n * constructor.\n * ====\n */\n function isContract(address account) internal view returns (bool) {\n // This method relies on extcodesize/address.code.length, which returns 0\n // for contracts in construction, since the code is only stored at the end\n // of the constructor execution.\n\n return account.code.length \u003e 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 \u003e= amount, \"Address: insufficient balance\");\n\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(\n address target,\n bytes memory data,\n string memory errorMessage\n ) 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(\n address target,\n bytes memory data,\n uint256 value\n ) 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(\n address target,\n bytes memory data,\n uint256 value,\n string memory errorMessage\n ) internal returns (bytes memory) {\n require(address(this).balance \u003e= value, \"Address: insufficient balance for call\");\n require(isContract(target), \"Address: call to non-contract\");\n\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(\n address target,\n bytes memory data,\n string memory errorMessage\n ) internal view returns (bytes memory) {\n require(isContract(target), \"Address: static call to non-contract\");\n\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResult(success, returndata, errorMessage);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n *\n * _Available since v3.4._\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionDelegateCall(target, data, \"Address: low-level delegate call failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n * but performing a delegate call.\n *\n * _Available since v3.4._\n */\n function functionDelegateCall(\n address target,\n bytes memory data,\n string memory errorMessage\n ) internal returns (bytes memory) {\n require(isContract(target), \"Address: delegate call to non-contract\");\n\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResult(success, returndata, errorMessage);\n }\n\n /**\n * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\n * revert reason using the provided one.\n *\n * _Available since v4.3._\n */\n function verifyCallResult(\n bool success,\n bytes memory returndata,\n string memory errorMessage\n ) internal 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 \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n\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\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n function safeTransfer(\n IERC20 token,\n address to,\n uint256 value\n ) internal {\n _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\n }\n\n function safeTransferFrom(\n IERC20 token,\n address from,\n address to,\n uint256 value\n ) internal {\n _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));\n }\n\n /**\n * @dev Deprecated. This function has issues similar to the ones found in\n * {IERC20-approve}, and its usage is discouraged.\n *\n * Whenever possible, use {safeIncreaseAllowance} and\n * {safeDecreaseAllowance} instead.\n */\n function safeApprove(\n IERC20 token,\n address spender,\n uint256 value\n ) internal {\n // safeApprove should only be called when setting an initial allowance,\n // or when resetting it to zero. To increase and decrease it, use\n // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\n require(\n (value == 0) || (token.allowance(address(this), spender) == 0),\n \"SafeERC20: approve from non-zero to non-zero allowance\"\n );\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\n }\n\n function safeIncreaseAllowance(\n IERC20 token,\n address spender,\n uint256 value\n ) internal {\n uint256 newAllowance = token.allowance(address(this), spender) + value;\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\n }\n\n function safeDecreaseAllowance(\n IERC20 token,\n address spender,\n uint256 value\n ) internal {\n unchecked {\n uint256 oldAllowance = token.allowance(address(this), spender);\n require(oldAllowance \u003e= value, \"SafeERC20: decreased allowance below zero\");\n uint256 newAllowance = oldAllowance - value;\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data, \"SafeERC20: low-level call failed\");\n if (returndata.length \u003e 0) {\n // Return data is optional\n require(abi.decode(returndata, (bool)), \"SafeERC20: ERC20 operation did not succeed\");\n }\n }\n}\n\ncontract MockTokenMessenger is TokenMessengerEvents, ITokenMessenger {\n using SafeERC20 for IERC20;\n\n address public override localMessageTransmitter;\n address public override localMinter;\n mapping(uint32 =\u003e bytes32) public remoteTokenMessenger;\n\n constructor(address localMessageTransmitter_) {\n localMessageTransmitter = localMessageTransmitter_;\n }\n\n function setLocalMinter(address localMinter_) external {\n localMinter = localMinter_;\n }\n\n function setRemoteTokenMessenger(uint32 remoteDomain, bytes32 remoteTokenMessenger_) external {\n remoteTokenMessenger[remoteDomain] = remoteTokenMessenger_;\n }\n\n function depositForBurnWithCaller(\n uint256 amount,\n uint32 destinationDomain,\n bytes32 mintRecipient,\n address burnToken,\n bytes32 destinationCaller\n ) external returns (uint64 nonce) {\n IERC20(burnToken).safeTransferFrom(msg.sender, localMinter, amount);\n ITokenMinter(localMinter).burn(burnToken, amount);\n bytes memory messageBody = formatTokenMessage(amount, mintRecipient, burnToken);\n nonce = IMessageTransmitter(localMessageTransmitter).sendMessageWithCaller(\n destinationDomain,\n remoteTokenMessenger[destinationDomain],\n destinationCaller,\n messageBody\n );\n emit DepositForBurn({\n nonce: nonce,\n burnToken: burnToken,\n amount: amount,\n depositor: msg.sender,\n mintRecipient: mintRecipient,\n destinationDomain: destinationDomain,\n destinationTokenMessenger: remoteTokenMessenger[destinationDomain],\n destinationCaller: destinationCaller\n });\n }\n\n function handleReceiveMessage(\n uint32 remoteDomain,\n bytes32 sender,\n bytes calldata messageBody\n ) external returns (bool success) {\n require(msg.sender == localMessageTransmitter, \"Invalid message transmitter\");\n require(sender == remoteTokenMessenger[remoteDomain], \"Remote TokenMessenger unsupported\");\n (uint256 amount, bytes32 mintRecipient, bytes32 burnToken) = abi.decode(\n messageBody,\n (uint256, bytes32, bytes32)\n );\n address mintToken = ITokenMinter(localMinter).mint(\n remoteDomain,\n burnToken,\n address(uint160(uint256(mintRecipient))),\n amount\n );\n emit MintAndWithdraw({\n mintRecipient: address(uint160(uint256(mintRecipient))),\n amount: amount,\n mintToken: mintToken\n });\n return true;\n }\n\n function formatTokenMessage(\n uint256 amount,\n bytes32 mintRecipient,\n address burnToken\n ) public pure returns (bytes memory tokenMessage) {\n return abi.encode(amount, mintRecipient, bytes32(uint256(uint160(burnToken))));\n }\n}\n","language":"Solidity","languageVersion":"0.8.17","compilerVersion":"0.8.17","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../","srcMap":"19825:3270:0:-:0;;;;;;;;;;;;;;;-1:-1:-1;;;19825:3270:0;;;;;;;;;;;;;;;;;","srcMapRuntime":"19825:3270:0:-:0;;;;;;;;","abiDefinition":[],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"details":"Wrappers around ERC20 operations that throw on failure (when the token contract returns false). Tokens that return no value (and instead revert or throw on failure) are also supported, non-reverting calls are assumed to be successful. To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract, which allows you to call the safe operations as `token.safeTransfer(...)`, etc.","kind":"dev","methods":{},"title":"SafeERC20","version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.17+commit.8df45f5f\"},\"language\":\"Solidity\",\"output\":{\"abi\":[],\"devdoc\":{\"details\":\"Wrappers around ERC20 operations that throw on failure (when the token contract returns false). Tokens that return no value (and instead revert or throw on failure) are also supported, non-reverting calls are assumed to be successful. To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract, which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\",\"kind\":\"dev\",\"methods\":{},\"title\":\"SafeERC20\",\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/MockTokenMessenger.sol\":\"SafeERC20\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/MockTokenMessenger.sol\":{\"keccak256\":\"0x676112f99e502493a5f5dddf4043b92d8baf8accb1bdc704a0e77529ddba46d6\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://b7f4c1c133460718570f7c97bf1f098cc47625b54e419be0bc87dcbc1863e3ce\",\"dweb:/ipfs/QmdAEfnnzhMPUcAaAGnG9zeY8KPpnLrR9PKx4VMSqb6Usx\"]}},\"version\":1}"},"hashes":{}},"solidity/MockTokenMessenger.sol:TokenMessengerEvents":{"code":"0x","runtime-code":"0x","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity 0.8.17;\n\nabstract contract TokenMessengerEvents {\n /**\n * @notice Emitted when a DepositForBurn message is sent\n * @param nonce unique nonce reserved by message\n * @param burnToken address of token burnt on source domain\n * @param amount deposit amount\n * @param depositor address where deposit is transferred from\n * @param mintRecipient address receiving minted tokens on destination domain as bytes32\n * @param destinationDomain destination domain\n * @param destinationTokenMessenger address of TokenMessenger on destination domain as bytes32\n * @param destinationCaller authorized caller as bytes32 of receiveMessage() on destination domain, if not equal to bytes32(0).\n * If equal to bytes32(0), any address can call receiveMessage().\n */\n event DepositForBurn(\n uint64 indexed nonce,\n address indexed burnToken,\n uint256 amount,\n address indexed depositor,\n bytes32 mintRecipient,\n uint32 destinationDomain,\n bytes32 destinationTokenMessenger,\n bytes32 destinationCaller\n );\n\n /**\n * @notice Emitted when tokens are minted\n * @param mintRecipient recipient address of minted tokens\n * @param amount amount of minted tokens\n * @param mintToken contract address of minted token\n */\n event MintAndWithdraw(address indexed mintRecipient, uint256 amount, address indexed mintToken);\n}\n\ninterface IMessageTransmitter {\n /**\n * @notice Receives an incoming message, validating the header and passing\n * the body to application-specific handler.\n * @param message The message raw bytes\n * @param signature The message signature\n * @return success bool, true if successful\n */\n function receiveMessage(bytes calldata message, bytes calldata signature) external returns (bool success);\n\n /**\n * @notice Sends an outgoing message from the source domain, with a specified caller on the\n * destination domain.\n * @dev Increment nonce, format the message, and emit `MessageSent` event with message information.\n * WARNING: if the `destinationCaller` does not represent a valid address as bytes32, then it will not be possible\n * to broadcast the message on the destination domain. This is an advanced feature, and the standard\n * sendMessage() should be preferred for use cases where a specific destination caller is not required.\n * @param destinationDomain Domain of destination chain\n * @param recipient Address of message recipient on destination domain as bytes32\n * @param destinationCaller caller on the destination domain, as bytes32\n * @param messageBody Raw bytes content of message\n * @return nonce reserved by message\n */\n function sendMessageWithCaller(\n uint32 destinationDomain,\n bytes32 recipient,\n bytes32 destinationCaller,\n bytes calldata messageBody\n ) external returns (uint64);\n\n // ═══════════════════════════════════════════════════ VIEWS ═══════════════════════════════════════════════════════\n\n // Domain of chain on which the contract is deployed\n function localDomain() external view returns (uint32);\n\n // Next available nonce from this source domain\n function nextAvailableNonce() external view returns (uint64);\n}\n\ninterface ITokenMessenger {\n /**\n * @notice Deposits and burns tokens from sender to be minted on destination domain. The mint\n * on the destination domain must be called by `destinationCaller`.\n * WARNING: if the `destinationCaller` does not represent a valid address as bytes32, then it will not be possible\n * to broadcast the message on the destination domain. This is an advanced feature, and the standard\n * depositForBurn() should be preferred for use cases where a specific destination caller is not required.\n * Emits a `DepositForBurn` event.\n * @dev reverts if:\n * - given destinationCaller is zero address\n * - given burnToken is not supported\n * - given destinationDomain has no TokenMessenger registered\n * - transferFrom() reverts. For example, if sender's burnToken balance or approved allowance\n * to this contract is less than `amount`.\n * - burn() reverts. For example, if `amount` is 0.\n * - MessageTransmitter returns false or reverts.\n * @param amount amount of tokens to burn\n * @param destinationDomain destination domain\n * @param mintRecipient address of mint recipient on destination domain\n * @param burnToken address of contract to burn deposited tokens, on local domain\n * @param destinationCaller caller on the destination domain, as bytes32\n * @return nonce unique nonce reserved by message\n */\n function depositForBurnWithCaller(\n uint256 amount,\n uint32 destinationDomain,\n bytes32 mintRecipient,\n address burnToken,\n bytes32 destinationCaller\n ) external returns (uint64 nonce);\n\n /**\n * @notice Handles an incoming message received by the local MessageTransmitter,\n * and takes the appropriate action. For a burn message, mints the\n * associated token to the requested recipient on the local domain.\n * @dev Validates the local sender is the local MessageTransmitter, and the\n * remote sender is a registered remote TokenMessenger for `remoteDomain`.\n * @param remoteDomain The domain where the message originated from.\n * @param sender The sender of the message (remote TokenMessenger).\n * @param messageBody The message body bytes.\n * @return success Bool, true if successful.\n */\n function handleReceiveMessage(\n uint32 remoteDomain,\n bytes32 sender,\n bytes calldata messageBody\n ) external returns (bool success);\n\n // ═══════════════════════════════════════════════════ VIEWS ═══════════════════════════════════════════════════════\n\n // Local Message Transmitter responsible for sending and receiving messages to/from remote domains\n function localMessageTransmitter() external view returns (address);\n\n // Minter responsible for minting and burning tokens on the local domain\n function localMinter() external view returns (address);\n}\n\ninterface ITokenMinter {\n /**\n * @notice Mints `amount` of local tokens corresponding to the\n * given (`sourceDomain`, `burnToken`) pair, to `to` address.\n * @dev reverts if the (`sourceDomain`, `burnToken`) pair does not\n * map to a nonzero local token address. This mapping can be queried using\n * getLocalToken().\n * @param sourceDomain Source domain where `burnToken` was burned.\n * @param burnToken Burned token address as bytes32.\n * @param to Address to receive minted tokens, corresponding to `burnToken`,\n * on this domain.\n * @param amount Amount of tokens to mint. Must be less than or equal\n * to the minterAllowance of this TokenMinter for given `_mintToken`.\n * @return mintToken token minted.\n */\n function mint(\n uint32 sourceDomain,\n bytes32 burnToken,\n address to,\n uint256 amount\n ) external returns (address mintToken);\n\n /**\n * @notice Burn tokens owned by this ITokenMinter.\n * @param burnToken burnable token.\n * @param amount amount of tokens to burn. Must be less than or equal to this ITokenMinter's\n * account balance of the given `_burnToken`.\n */\n function burn(address burnToken, uint256 amount) external;\n\n /**\n * @notice Get the local token associated with the given remote domain and token.\n * @param remoteDomain Remote domain\n * @param remoteToken Remote token\n * @return local token address\n */\n function getLocalToken(uint32 remoteDomain, bytes32 remoteToken) external view returns (address);\n\n // local token (address) =\u003e maximum burn amounts per message\n function burnLimitsPerMessage(address token) external view returns (uint256);\n}\n\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/utils/SafeERC20.sol)\n\n// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\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(\n address from,\n address to,\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\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\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 * [IMPORTANT]\n * ====\n * You shouldn't rely on `isContract` to protect against flash loan attacks!\n *\n * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\n * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\n * constructor.\n * ====\n */\n function isContract(address account) internal view returns (bool) {\n // This method relies on extcodesize/address.code.length, which returns 0\n // for contracts in construction, since the code is only stored at the end\n // of the constructor execution.\n\n return account.code.length \u003e 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 \u003e= amount, \"Address: insufficient balance\");\n\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(\n address target,\n bytes memory data,\n string memory errorMessage\n ) 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(\n address target,\n bytes memory data,\n uint256 value\n ) 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(\n address target,\n bytes memory data,\n uint256 value,\n string memory errorMessage\n ) internal returns (bytes memory) {\n require(address(this).balance \u003e= value, \"Address: insufficient balance for call\");\n require(isContract(target), \"Address: call to non-contract\");\n\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(\n address target,\n bytes memory data,\n string memory errorMessage\n ) internal view returns (bytes memory) {\n require(isContract(target), \"Address: static call to non-contract\");\n\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResult(success, returndata, errorMessage);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n *\n * _Available since v3.4._\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionDelegateCall(target, data, \"Address: low-level delegate call failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n * but performing a delegate call.\n *\n * _Available since v3.4._\n */\n function functionDelegateCall(\n address target,\n bytes memory data,\n string memory errorMessage\n ) internal returns (bytes memory) {\n require(isContract(target), \"Address: delegate call to non-contract\");\n\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResult(success, returndata, errorMessage);\n }\n\n /**\n * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\n * revert reason using the provided one.\n *\n * _Available since v4.3._\n */\n function verifyCallResult(\n bool success,\n bytes memory returndata,\n string memory errorMessage\n ) internal 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 \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n\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\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n function safeTransfer(\n IERC20 token,\n address to,\n uint256 value\n ) internal {\n _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\n }\n\n function safeTransferFrom(\n IERC20 token,\n address from,\n address to,\n uint256 value\n ) internal {\n _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));\n }\n\n /**\n * @dev Deprecated. This function has issues similar to the ones found in\n * {IERC20-approve}, and its usage is discouraged.\n *\n * Whenever possible, use {safeIncreaseAllowance} and\n * {safeDecreaseAllowance} instead.\n */\n function safeApprove(\n IERC20 token,\n address spender,\n uint256 value\n ) internal {\n // safeApprove should only be called when setting an initial allowance,\n // or when resetting it to zero. To increase and decrease it, use\n // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\n require(\n (value == 0) || (token.allowance(address(this), spender) == 0),\n \"SafeERC20: approve from non-zero to non-zero allowance\"\n );\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\n }\n\n function safeIncreaseAllowance(\n IERC20 token,\n address spender,\n uint256 value\n ) internal {\n uint256 newAllowance = token.allowance(address(this), spender) + value;\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\n }\n\n function safeDecreaseAllowance(\n IERC20 token,\n address spender,\n uint256 value\n ) internal {\n unchecked {\n uint256 oldAllowance = token.allowance(address(this), spender);\n require(oldAllowance \u003e= value, \"SafeERC20: decreased allowance below zero\");\n uint256 newAllowance = oldAllowance - value;\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data, \"SafeERC20: low-level call failed\");\n if (returndata.length \u003e 0) {\n // Return data is optional\n require(abi.decode(returndata, (bool)), \"SafeERC20: ERC20 operation did not succeed\");\n }\n }\n}\n\ncontract MockTokenMessenger is TokenMessengerEvents, ITokenMessenger {\n using SafeERC20 for IERC20;\n\n address public override localMessageTransmitter;\n address public override localMinter;\n mapping(uint32 =\u003e bytes32) public remoteTokenMessenger;\n\n constructor(address localMessageTransmitter_) {\n localMessageTransmitter = localMessageTransmitter_;\n }\n\n function setLocalMinter(address localMinter_) external {\n localMinter = localMinter_;\n }\n\n function setRemoteTokenMessenger(uint32 remoteDomain, bytes32 remoteTokenMessenger_) external {\n remoteTokenMessenger[remoteDomain] = remoteTokenMessenger_;\n }\n\n function depositForBurnWithCaller(\n uint256 amount,\n uint32 destinationDomain,\n bytes32 mintRecipient,\n address burnToken,\n bytes32 destinationCaller\n ) external returns (uint64 nonce) {\n IERC20(burnToken).safeTransferFrom(msg.sender, localMinter, amount);\n ITokenMinter(localMinter).burn(burnToken, amount);\n bytes memory messageBody = formatTokenMessage(amount, mintRecipient, burnToken);\n nonce = IMessageTransmitter(localMessageTransmitter).sendMessageWithCaller(\n destinationDomain,\n remoteTokenMessenger[destinationDomain],\n destinationCaller,\n messageBody\n );\n emit DepositForBurn({\n nonce: nonce,\n burnToken: burnToken,\n amount: amount,\n depositor: msg.sender,\n mintRecipient: mintRecipient,\n destinationDomain: destinationDomain,\n destinationTokenMessenger: remoteTokenMessenger[destinationDomain],\n destinationCaller: destinationCaller\n });\n }\n\n function handleReceiveMessage(\n uint32 remoteDomain,\n bytes32 sender,\n bytes calldata messageBody\n ) external returns (bool success) {\n require(msg.sender == localMessageTransmitter, \"Invalid message transmitter\");\n require(sender == remoteTokenMessenger[remoteDomain], \"Remote TokenMessenger unsupported\");\n (uint256 amount, bytes32 mintRecipient, bytes32 burnToken) = abi.decode(\n messageBody,\n (uint256, bytes32, bytes32)\n );\n address mintToken = ITokenMinter(localMinter).mint(\n remoteDomain,\n burnToken,\n address(uint160(uint256(mintRecipient))),\n amount\n );\n emit MintAndWithdraw({\n mintRecipient: address(uint160(uint256(mintRecipient))),\n amount: amount,\n mintToken: mintToken\n });\n return true;\n }\n\n function formatTokenMessage(\n uint256 amount,\n bytes32 mintRecipient,\n address burnToken\n ) public pure returns (bytes memory tokenMessage) {\n return abi.encode(amount, mintRecipient, bytes32(uint256(uint160(burnToken))));\n }\n}\n","language":"Solidity","languageVersion":"0.8.17","compilerVersion":"0.8.17","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../","srcMap":"","srcMapRuntime":"","abiDefinition":[{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint64","name":"nonce","type":"uint64"},{"indexed":true,"internalType":"address","name":"burnToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":true,"internalType":"address","name":"depositor","type":"address"},{"indexed":false,"internalType":"bytes32","name":"mintRecipient","type":"bytes32"},{"indexed":false,"internalType":"uint32","name":"destinationDomain","type":"uint32"},{"indexed":false,"internalType":"bytes32","name":"destinationTokenMessenger","type":"bytes32"},{"indexed":false,"internalType":"bytes32","name":"destinationCaller","type":"bytes32"}],"name":"DepositForBurn","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"mintRecipient","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":true,"internalType":"address","name":"mintToken","type":"address"}],"name":"MintAndWithdraw","type":"event"}],"userDoc":{"events":{"DepositForBurn(uint64,address,uint256,address,bytes32,uint32,bytes32,bytes32)":{"notice":"Emitted when a DepositForBurn message is sent"},"MintAndWithdraw(address,uint256,address)":{"notice":"Emitted when tokens are minted"}},"kind":"user","methods":{},"version":1},"developerDoc":{"events":{"DepositForBurn(uint64,address,uint256,address,bytes32,uint32,bytes32,bytes32)":{"params":{"amount":"deposit amount","burnToken":"address of token burnt on source domain","depositor":"address where deposit is transferred from","destinationCaller":"authorized caller as bytes32 of receiveMessage() on destination domain, if not equal to bytes32(0). If equal to bytes32(0), any address can call receiveMessage().","destinationDomain":"destination domain","destinationTokenMessenger":"address of TokenMessenger on destination domain as bytes32","mintRecipient":"address receiving minted tokens on destination domain as bytes32","nonce":"unique nonce reserved by message"}},"MintAndWithdraw(address,uint256,address)":{"params":{"amount":"amount of minted tokens","mintRecipient":"recipient address of minted tokens","mintToken":"contract address of minted token"}}},"kind":"dev","methods":{},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.17+commit.8df45f5f\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint64\",\"name\":\"nonce\",\"type\":\"uint64\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"burnToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"mintRecipient\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"destinationDomain\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"destinationTokenMessenger\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"destinationCaller\",\"type\":\"bytes32\"}],\"name\":\"DepositForBurn\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"mintRecipient\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"mintToken\",\"type\":\"address\"}],\"name\":\"MintAndWithdraw\",\"type\":\"event\"}],\"devdoc\":{\"events\":{\"DepositForBurn(uint64,address,uint256,address,bytes32,uint32,bytes32,bytes32)\":{\"params\":{\"amount\":\"deposit amount\",\"burnToken\":\"address of token burnt on source domain\",\"depositor\":\"address where deposit is transferred from\",\"destinationCaller\":\"authorized caller as bytes32 of receiveMessage() on destination domain, if not equal to bytes32(0). If equal to bytes32(0), any address can call receiveMessage().\",\"destinationDomain\":\"destination domain\",\"destinationTokenMessenger\":\"address of TokenMessenger on destination domain as bytes32\",\"mintRecipient\":\"address receiving minted tokens on destination domain as bytes32\",\"nonce\":\"unique nonce reserved by message\"}},\"MintAndWithdraw(address,uint256,address)\":{\"params\":{\"amount\":\"amount of minted tokens\",\"mintRecipient\":\"recipient address of minted tokens\",\"mintToken\":\"contract address of minted token\"}}},\"kind\":\"dev\",\"methods\":{},\"version\":1},\"userdoc\":{\"events\":{\"DepositForBurn(uint64,address,uint256,address,bytes32,uint32,bytes32,bytes32)\":{\"notice\":\"Emitted when a DepositForBurn message is sent\"},\"MintAndWithdraw(address,uint256,address)\":{\"notice\":\"Emitted when tokens are minted\"}},\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/MockTokenMessenger.sol\":\"TokenMessengerEvents\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/MockTokenMessenger.sol\":{\"keccak256\":\"0x676112f99e502493a5f5dddf4043b92d8baf8accb1bdc704a0e77529ddba46d6\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://b7f4c1c133460718570f7c97bf1f098cc47625b54e419be0bc87dcbc1863e3ce\",\"dweb:/ipfs/QmdAEfnnzhMPUcAaAGnG9zeY8KPpnLrR9PKx4VMSqb6Usx\"]}},\"version\":1}"},"hashes":{}}}