diff --git a/contracts/SpokePoolVerifier.sol b/contracts/SpokePoolVerifier.sol index 721ab7336..5dc333684 100644 --- a/contracts/SpokePoolVerifier.sol +++ b/contracts/SpokePoolVerifier.sol @@ -2,7 +2,7 @@ pragma solidity ^0.8.0; import "@openzeppelin/contracts/utils/Address.sol"; -import "./interfaces/SpokePoolInterface.sol"; +import "./interfaces/V3SpokePoolInterface.sol"; /** * @notice SpokePoolVerifier is a contract that verifies that the SpokePool exists on this chain before sending ETH to it. @@ -15,6 +15,9 @@ import "./interfaces/SpokePoolInterface.sol"; contract SpokePoolVerifier { using Address for address; + error InvalidMsgValue(); + error InvalidSpokePool(); + /** * @notice Passthrough function to `depositV3()` on the SpokePool contract. * @dev Protects the caller from losing their ETH (or other native token) by reverting if the SpokePool address @@ -23,41 +26,51 @@ contract SpokePoolVerifier { * This contract should only be used for native token deposits, as this problem only exists for native tokens. * @param spokePool Address of the SpokePool contract that the user is intending to call. * @param recipient Address to receive funds at on destination chain. - * @param originToken Token to lock into this contract to initiate deposit. - * @param amount Amount of tokens to deposit. Will be amount of tokens to receive less fees. + * @param inputToken Token to lock into this contract to initiate deposit. + * @param inputAmount Amount of tokens to deposit. + * @param outputAmount Amount of tokens to receive on destination chain. * @param destinationChainId Denotes network where user will receive funds from SpokePool by a relayer. - * @param relayerFeePct % of deposit amount taken out to incentivize a fast relayer. * @param quoteTimestamp Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid * to LP pool on HubPool. * @param message Arbitrary data that can be used to pass additional information to the recipient along with the tokens. * Note: this is intended to be used to pass along instructions for how a contract should use or allocate the tokens. - * @param maxCount used to protect the depositor from frontrunning to guarantee their quote remains valid. - * Note: this is intended to be used to pass along instructions for how a contract should use or allocate the tokens. + * @param exclusiveRelayer Address of the relayer who has exclusive rights to fill this deposit. Can be set to + * 0x0 if no exclusivity period is desired. If so, then must set exclusivityDeadline to 0. + * @param exclusivityDeadline Timestamp after which any relayer can fill this deposit. Must set + * to 0 if exclusiveRelayer is set to 0x0, and vice versa. + * @param fillDeadline Timestamp after which this deposit can no longer be filled. */ function deposit( - SpokePoolInterface spokePool, + V3SpokePoolInterface spokePool, address recipient, - address originToken, - uint256 amount, + address inputToken, + uint256 inputAmount, + uint256 outputAmount, uint256 destinationChainId, - int64 relayerFeePct, + address exclusiveRelayer, uint32 quoteTimestamp, - bytes memory message, - uint256 maxCount + uint32 fillDeadline, + uint32 exclusivityDeadline, + bytes memory message ) external payable { - require(msg.value == amount, "msg.value != amount"); - require(address(spokePool).isContract(), "spokePool is not a contract"); + if (msg.value != inputAmount) revert InvalidMsgValue(); + if (!address(spokePool).isContract()) revert InvalidSpokePool(); // Set msg.sender as the depositor so that msg.sender can speed up the deposit. - spokePool.depositFor{ value: msg.value }( + spokePool.depositV3{ value: msg.value }( msg.sender, recipient, - originToken, - amount, + inputToken, + // @dev Setting outputToken to 0x0 to instruct fillers to use the equivalent token + // as the originToken on the destination chain. + address(0), + inputAmount, + outputAmount, destinationChainId, - relayerFeePct, + exclusiveRelayer, quoteTimestamp, - message, - maxCount + fillDeadline, + exclusivityDeadline, + message ); } } diff --git a/deploy/023_deploy_spoke_pool_verifier.ts b/deploy/023_deploy_spoke_pool_verifier.ts index d8605a6c6..4338c15f9 100644 --- a/deploy/023_deploy_spoke_pool_verifier.ts +++ b/deploy/023_deploy_spoke_pool_verifier.ts @@ -7,13 +7,15 @@ const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) { const { deployer } = await getNamedAccounts(); - await deploy("SpokePoolVerifier", { + const deployment = await deploy("SpokePoolVerifier", { from: deployer, log: true, skipIfAlreadyDeployed: true, deterministicDeployment: "0x1234", // Salt for the create2 call. }); + console.log(`Deployed at block ${deployment.receipt.blockNumber} (tx: ${deployment.transactionHash})`); + await run("verify:verify", { address: deployment.address, constructorArguments: [] }); }; module.exports = func; -func.tags = ["SpokePoolVerifier", "polygon", "mainnet", "optimism", "arbitrum", "zksync"]; +func.tags = ["SpokePoolVerifier"]; diff --git a/deployments/arbitrum/SpokePoolVerifier.json b/deployments/arbitrum/SpokePoolVerifier.json index ccaa14b30..845334bdc 100644 --- a/deployments/arbitrum/SpokePoolVerifier.json +++ b/deployments/arbitrum/SpokePoolVerifier.json @@ -1,10 +1,10 @@ { - "address": "0xB4A8d45647445EA9FC3E1058096142390683dBC2", + "address": "0x4437A1Ee2dFb72954F21A44C3F0F0E2CBA5A5C27", "abi": [ { "inputs": [ { - "internalType": "contract SpokePoolInterface", + "internalType": "contract V3SpokePoolInterface", "name": "spokePool", "type": "address" }, @@ -15,12 +15,17 @@ }, { "internalType": "address", - "name": "originToken", + "name": "inputToken", "type": "address" }, { "internalType": "uint256", - "name": "amount", + "name": "inputAmount", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "outputAmount", "type": "uint256" }, { @@ -29,24 +34,29 @@ "type": "uint256" }, { - "internalType": "int64", - "name": "relayerFeePct", - "type": "int64" + "internalType": "address", + "name": "exclusiveRelayer", + "type": "address" }, { "internalType": "uint32", "name": "quoteTimestamp", "type": "uint32" }, + { + "internalType": "uint32", + "name": "fillDeadline", + "type": "uint32" + }, + { + "internalType": "uint32", + "name": "exclusivityDeadline", + "type": "uint32" + }, { "internalType": "bytes", "name": "message", "type": "bytes" - }, - { - "internalType": "uint256", - "name": "maxCount", - "type": "uint256" } ], "name": "deposit", @@ -55,43 +65,46 @@ "type": "function" } ], - "transactionHash": "0x166aad3d952cd43cb4ae8c3a809c5c8e082f051934ec1d673f35eb1e9bed7f28", + "transactionHash": "0x045ca094515430af603809611a8382edcb7c7b8cc3948736440e1e7767cf8148", "receipt": { "to": "0x4e59b44847b379578588920cA78FbF26c0B4956C", "from": "0x9A8f92a830A5cB89a3816e3D267CB7791c16b04D", "contractAddress": null, "transactionIndex": 3, - "gasUsed": "565599", + "gasUsed": "309737", "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - "blockHash": "0x55e740ca6e8abc0fc871432efe005f6d7098c10ecf3d478f9cb6a0d827cfb2aa", - "transactionHash": "0x166aad3d952cd43cb4ae8c3a809c5c8e082f051934ec1d673f35eb1e9bed7f28", + "blockHash": "0x301272446ef6305ba45f85de5d49ce1d32d0aeb7b950be22905531fe563fd4f1", + "transactionHash": "0x045ca094515430af603809611a8382edcb7c7b8cc3948736440e1e7767cf8148", "logs": [], - "blockNumber": 194021369, - "cumulativeGasUsed": "1251510", + "blockNumber": 236320356, + "cumulativeGasUsed": "544298", "status": 1, "byzantium": true }, "args": [], - "numDeployments": 3, - "solcInputHash": "53ab13385da43753d9a657e7780a0560", - "metadata": "{\"compiler\":{\"version\":\"0.8.19+commit.7dd6d404\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"contract SpokePoolInterface\",\"name\":\"spokePool\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"internalType\":\"int64\",\"name\":\"relayerFeePct\",\"type\":\"int64\"},{\"internalType\":\"uint32\",\"name\":\"quoteTimestamp\",\"type\":\"uint32\"},{\"internalType\":\"bytes\",\"name\":\"message\",\"type\":\"bytes\"},{\"internalType\":\"uint256\",\"name\":\"maxCount\",\"type\":\"uint256\"}],\"name\":\"deposit\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"This contract must be deployed via Create2 to the same address on all chains. That way, an errant transaction sent to the wrong chain will be blocked by this contract rather than hitting a dead address. This means that this contract will not work to protect chains, like zkSync, where Create2 address derivations don't match other chains. Source: https://era.zksync.io/docs/reference/architecture/differences-with-ethereum.html#create-create2\",\"kind\":\"dev\",\"methods\":{\"deposit(address,address,address,uint256,uint256,int64,uint32,bytes,uint256)\":{\"details\":\"Protects the caller from losing their ETH (or other native token) by reverting if the SpokePool address they intended to call does not exist on this chain. Because this contract can be deployed at the same address everywhere callers should be protected even if the transaction is submitted to an unintended network. This contract should only be used for native token deposits, as this problem only exists for native tokens.\",\"params\":{\"amount\":\"Amount of tokens to deposit. Will be amount of tokens to receive less fees.\",\"destinationChainId\":\"Denotes network where user will receive funds from SpokePool by a relayer.\",\"maxCount\":\"used to protect the depositor from frontrunning to guarantee their quote remains valid. Note: this is intended to be used to pass along instructions for how a contract should use or allocate the tokens.\",\"message\":\"Arbitrary data that can be used to pass additional information to the recipient along with the tokens. Note: this is intended to be used to pass along instructions for how a contract should use or allocate the tokens.\",\"originToken\":\"Token to lock into this contract to initiate deposit.\",\"quoteTimestamp\":\"Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid to LP pool on HubPool.\",\"recipient\":\"Address to receive funds at on destination chain.\",\"relayerFeePct\":\"% of deposit amount taken out to incentivize a fast relayer.\",\"spokePool\":\"Address of the SpokePool contract that the user is intending to call.\"}}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"deposit(address,address,address,uint256,uint256,int64,uint32,bytes,uint256)\":{\"notice\":\"Passthrough function to `depositV3()` on the SpokePool contract.\"}},\"notice\":\"SpokePoolVerifier is a contract that verifies that the SpokePool exists on this chain before sending ETH to it.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/SpokePoolVerifier.sol\":\"SpokePoolVerifier\"},\"debug\":{\"revertStrings\":\"strip\"},\"evmVersion\":\"paris\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":1000000},\"remappings\":[],\"viaIR\":true},\"sources\":{\"@openzeppelin/contracts/utils/Address.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.9.0) (utils/Address.sol)\\n\\npragma solidity ^0.8.1;\\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 * Furthermore, `isContract` will also return true if the target contract within\\n * the same transaction is already scheduled for destruction by `SELFDESTRUCT`,\\n * which only has an effect at the end of a transaction.\\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 > 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://consensys.net/diligence/blog/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.8.0/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\\n */\\n function sendValue(address payable recipient, uint256 amount) internal {\\n require(address(this).balance >= amount, \\\"Address: insufficient balance\\\");\\n\\n (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 functionCallWithValue(target, data, 0, \\\"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(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, value, \\\"Address: low-level call with value failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\\n * with `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(address(this).balance >= value, \\\"Address: insufficient balance for call\\\");\\n (bool success, bytes memory returndata) = target.call{value: value}(data);\\n return verifyCallResultFromTarget(target, 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 (bool success, bytes memory returndata) = target.staticcall(data);\\n return verifyCallResultFromTarget(target, 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 (bool success, bytes memory returndata) = target.delegatecall(data);\\n return verifyCallResultFromTarget(target, success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling\\n * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.\\n *\\n * _Available since v4.8._\\n */\\n function verifyCallResultFromTarget(\\n address target,\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n if (success) {\\n if (returndata.length == 0) {\\n // only check isContract if the call was successful and the return data is empty\\n // otherwise we already know that it was a contract\\n require(isContract(target), \\\"Address: call to non-contract\\\");\\n }\\n return returndata;\\n } else {\\n _revert(returndata, errorMessage);\\n }\\n }\\n\\n /**\\n * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the\\n * revert reason or 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 _revert(returndata, errorMessage);\\n }\\n }\\n\\n function _revert(bytes memory returndata, string memory errorMessage) private pure {\\n // Look for revert reason and bubble it up if present\\n if (returndata.length > 0) {\\n // The easiest way to bubble the revert reason is using memory via assembly\\n /// @solidity memory-safe-assembly\\n assembly {\\n let returndata_size := mload(returndata)\\n revert(add(32, returndata), returndata_size)\\n }\\n } else {\\n revert(errorMessage);\\n }\\n }\\n}\\n\",\"keccak256\":\"0x006dd67219697fe68d7fbfdea512e7c4cb64a43565ed86171d67e844982da6fa\",\"license\":\"MIT\"},\"contracts/SpokePoolVerifier.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\nimport \\\"@openzeppelin/contracts/utils/Address.sol\\\";\\nimport \\\"./interfaces/SpokePoolInterface.sol\\\";\\n\\n/**\\n * @notice SpokePoolVerifier is a contract that verifies that the SpokePool exists on this chain before sending ETH to it.\\n * @dev This contract must be deployed via Create2 to the same address on all chains. That way, an errant transaction sent\\n * to the wrong chain will be blocked by this contract rather than hitting a dead address. This means that this contract\\n * will not work to protect chains, like zkSync, where Create2 address derivations don't match other chains.\\n * Source: https://era.zksync.io/docs/reference/architecture/differences-with-ethereum.html#create-create2\\n */\\ncontract SpokePoolVerifier {\\n using Address for address;\\n\\n /**\\n * @notice Passthrough function to `depositV3()` on the SpokePool contract.\\n * @dev Protects the caller from losing their ETH (or other native token) by reverting if the SpokePool address\\n * they intended to call does not exist on this chain. Because this contract can be deployed at the same address\\n * everywhere callers should be protected even if the transaction is submitted to an unintended network.\\n * This contract should only be used for native token deposits, as this problem only exists for native tokens.\\n * @param spokePool Address of the SpokePool contract that the user is intending to call.\\n * @param recipient Address to receive funds at on destination chain.\\n * @param originToken Token to lock into this contract to initiate deposit.\\n * @param amount Amount of tokens to deposit. Will be amount of tokens to receive less fees.\\n * @param destinationChainId Denotes network where user will receive funds from SpokePool by a relayer.\\n * @param relayerFeePct % of deposit amount taken out to incentivize a fast relayer.\\n * @param quoteTimestamp Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid\\n * to LP pool on HubPool.\\n * @param message Arbitrary data that can be used to pass additional information to the recipient along with the tokens.\\n * Note: this is intended to be used to pass along instructions for how a contract should use or allocate the tokens.\\n * @param maxCount used to protect the depositor from frontrunning to guarantee their quote remains valid.\\n * Note: this is intended to be used to pass along instructions for how a contract should use or allocate the tokens.\\n */\\n function deposit(\\n SpokePoolInterface spokePool,\\n address recipient,\\n address originToken,\\n uint256 amount,\\n uint256 destinationChainId,\\n int64 relayerFeePct,\\n uint32 quoteTimestamp,\\n bytes memory message,\\n uint256 maxCount\\n ) external payable {\\n require(msg.value == amount, \\\"msg.value != amount\\\");\\n require(address(spokePool).isContract(), \\\"spokePool is not a contract\\\");\\n // Set msg.sender as the depositor so that msg.sender can speed up the deposit.\\n spokePool.depositFor{ value: msg.value }(\\n msg.sender,\\n recipient,\\n originToken,\\n amount,\\n destinationChainId,\\n relayerFeePct,\\n quoteTimestamp,\\n message,\\n maxCount\\n );\\n }\\n}\\n\",\"keccak256\":\"0xfc008c31a2fde7eb0daedaa823b76931225f41ac882b6d1c515d8a38ccda60ec\",\"license\":\"BUSL-1.1\"},\"contracts/interfaces/SpokePoolInterface.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\n/**\\n * @notice Contains common data structures and functions used by all SpokePool implementations.\\n */\\ninterface SpokePoolInterface {\\n // This leaf is meant to be decoded in the SpokePool to pay out successful relayers.\\n struct RelayerRefundLeaf {\\n // This is the amount to return to the HubPool. This occurs when there is a PoolRebalanceLeaf netSendAmount that\\n // is negative. This is just the negative of this value.\\n uint256 amountToReturn;\\n // Used to verify that this is being executed on the correct destination chainId.\\n uint256 chainId;\\n // This array designates how much each of those addresses should be refunded.\\n uint256[] refundAmounts;\\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\\n uint32 leafId;\\n // The associated L2TokenAddress that these claims apply to.\\n address l2TokenAddress;\\n // Must be same length as refundAmounts and designates each address that must be refunded.\\n address[] refundAddresses;\\n }\\n\\n // Stores collection of merkle roots that can be published to this contract from the HubPool, which are referenced\\n // by \\\"data workers\\\" via inclusion proofs to execute leaves in the roots.\\n struct RootBundle {\\n // Merkle root of slow relays that were not fully filled and whose recipient is still owed funds from the LP pool.\\n bytes32 slowRelayRoot;\\n // Merkle root of relayer refunds for successful relays.\\n bytes32 relayerRefundRoot;\\n // This is a 2D bitmap tracking which leaves in the relayer refund root have been claimed, with max size of\\n // 256x(2^248) leaves per root.\\n mapping(uint256 => uint256) claimedBitmap;\\n }\\n\\n function setCrossDomainAdmin(address newCrossDomainAdmin) external;\\n\\n function setHubPool(address newHubPool) external;\\n\\n function setEnableRoute(\\n address originToken,\\n uint256 destinationChainId,\\n bool enable\\n ) external;\\n\\n function pauseDeposits(bool pause) external;\\n\\n function pauseFills(bool pause) external;\\n\\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) external;\\n\\n function emergencyDeleteRootBundle(uint256 rootBundleId) external;\\n\\n function deposit(\\n address recipient,\\n address originToken,\\n uint256 amount,\\n uint256 destinationChainId,\\n int64 relayerFeePct,\\n uint32 quoteTimestamp,\\n bytes memory message,\\n uint256 maxCount\\n ) external payable;\\n\\n function depositFor(\\n address depositor,\\n address recipient,\\n address originToken,\\n uint256 amount,\\n uint256 destinationChainId,\\n int64 relayerFeePct,\\n uint32 quoteTimestamp,\\n bytes memory message,\\n uint256 maxCount\\n ) external payable;\\n\\n function executeRelayerRefundLeaf(\\n uint32 rootBundleId,\\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\\n bytes32[] memory proof\\n ) external payable;\\n\\n function chainId() external view returns (uint256);\\n\\n error NotEOA();\\n error InvalidDepositorSignature();\\n error InvalidRelayerFeePct();\\n error MaxTransferSizeExceeded();\\n error InvalidCrossDomainAdmin();\\n error InvalidHubPool();\\n error DepositsArePaused();\\n error FillsArePaused();\\n}\\n\",\"keccak256\":\"0xc90fbd7e66e2e87e9aacbe93c20cc020cd1fc582c4fd4879807e7dc026943ea0\",\"license\":\"BUSL-1.1\"}},\"version\":1}", - "bytecode": "0x608080604052346100165761034b908161001c8239f35b600080fdfe600436101561000d57600080fd5b6000803560e01c63e0db3fcf1461002357600080fd5b610120807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103115773ffffffffffffffffffffffffffffffffffffffff600435818116810361030d576024359282841684036103095760443583811681036103055760a4358060070b81036103015760c4359063ffffffff8216820361029b5760e43567ffffffffffffffff81116102fd57366023820112156102fd57806004013567ffffffffffffffff81116102d0577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0603f81601f84011601166080016080811067ffffffffffffffff8211176102a357908a929160405280608052366024828401011161029f57602091819060240160a0376080010152606435340361029b578585163b1561029b578585163b1561029b57859694929163ffffffff91878a9896946040519a8b997f541f4f14000000000000000000000000000000000000000000000000000000008b523360048c01521660248a01521660448801526064356064880152608435608488015260070b60a48701521660c485015260e484015260805180610124850152845b8181106102805750908391827fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f6101449389858286010152610104803590850152011681010301923491165af1801561027557610233575080f35b67ffffffffffffffff81116102485760405280f35b6024827f4e487b710000000000000000000000000000000000000000000000000000000081526041600452fd5b6040513d84823e3d90fd5b60a081015187820161014401528795508694506020016101d6565b8780fd5b8280fd5b60248b7f4e487b710000000000000000000000000000000000000000000000000000000081526041600452fd5b60248a7f4e487b710000000000000000000000000000000000000000000000000000000081526041600452fd5b8880fd5b8680fd5b8580fd5b8480fd5b8380fd5b5080fdfea26469706673582212204f81f550f00970671d0755020f959a6599fd76306000e67b424172e1089b949a64736f6c63430008130033", - "deployedBytecode": "0x600436101561000d57600080fd5b6000803560e01c63e0db3fcf1461002357600080fd5b610120807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103115773ffffffffffffffffffffffffffffffffffffffff600435818116810361030d576024359282841684036103095760443583811681036103055760a4358060070b81036103015760c4359063ffffffff8216820361029b5760e43567ffffffffffffffff81116102fd57366023820112156102fd57806004013567ffffffffffffffff81116102d0577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0603f81601f84011601166080016080811067ffffffffffffffff8211176102a357908a929160405280608052366024828401011161029f57602091819060240160a0376080010152606435340361029b578585163b1561029b578585163b1561029b57859694929163ffffffff91878a9896946040519a8b997f541f4f14000000000000000000000000000000000000000000000000000000008b523360048c01521660248a01521660448801526064356064880152608435608488015260070b60a48701521660c485015260e484015260805180610124850152845b8181106102805750908391827fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f6101449389858286010152610104803590850152011681010301923491165af1801561027557610233575080f35b67ffffffffffffffff81116102485760405280f35b6024827f4e487b710000000000000000000000000000000000000000000000000000000081526041600452fd5b6040513d84823e3d90fd5b60a081015187820161014401528795508694506020016101d6565b8780fd5b8280fd5b60248b7f4e487b710000000000000000000000000000000000000000000000000000000081526041600452fd5b60248a7f4e487b710000000000000000000000000000000000000000000000000000000081526041600452fd5b8880fd5b8680fd5b8580fd5b8480fd5b8380fd5b5080fdfea26469706673582212204f81f550f00970671d0755020f959a6599fd76306000e67b424172e1089b949a64736f6c63430008130033", + "numDeployments": 5, + "solcInputHash": "783274f805324492b21545b62eb0dbfe", + "metadata": "{\"compiler\":{\"version\":\"0.8.19+commit.7dd6d404\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"contract V3SpokePoolInterface\",\"name\":\"spokePool\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"inputToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"inputAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"outputAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"exclusiveRelayer\",\"type\":\"address\"},{\"internalType\":\"uint32\",\"name\":\"quoteTimestamp\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"fillDeadline\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"exclusivityDeadline\",\"type\":\"uint32\"},{\"internalType\":\"bytes\",\"name\":\"message\",\"type\":\"bytes\"}],\"name\":\"deposit\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"}],\"devdoc\":{\"custom:security-contact\":\"bugs@across.to\",\"details\":\"This contract must be deployed via Create2 to the same address on all chains. That way, an errant transaction sent to the wrong chain will be blocked by this contract rather than hitting a dead address. This means that this contract will not work to protect chains, like zkSync, where Create2 address derivations don't match other chains. Source: https://era.zksync.io/docs/reference/architecture/differences-with-ethereum.html#create-create2\",\"kind\":\"dev\",\"methods\":{\"deposit(address,address,address,uint256,uint256,uint256,address,uint32,uint32,uint32,bytes)\":{\"details\":\"Protects the caller from losing their ETH (or other native token) by reverting if the SpokePool address they intended to call does not exist on this chain. Because this contract can be deployed at the same address everywhere callers should be protected even if the transaction is submitted to an unintended network. This contract should only be used for native token deposits, as this problem only exists for native tokens.\",\"params\":{\"destinationChainId\":\"Denotes network where user will receive funds from SpokePool by a relayer.\",\"exclusiveRelayer\":\"Address of the relayer who has exclusive rights to fill this deposit. Can be set to 0x0 if no exclusivity period is desired. If so, then must set exclusivityDeadline to 0.\",\"exclusivityDeadline\":\"Timestamp after which any relayer can fill this deposit. Must set to 0 if exclusiveRelayer is set to 0x0, and vice versa.\",\"fillDeadline\":\"Timestamp after which this deposit can no longer be filled.\",\"inputAmount\":\"Amount of tokens to deposit.\",\"inputToken\":\"Token to lock into this contract to initiate deposit.\",\"message\":\"Arbitrary data that can be used to pass additional information to the recipient along with the tokens. Note: this is intended to be used to pass along instructions for how a contract should use or allocate the tokens.\",\"outputAmount\":\"Amount of tokens to receive on destination chain.\",\"quoteTimestamp\":\"Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid to LP pool on HubPool.\",\"recipient\":\"Address to receive funds at on destination chain.\",\"spokePool\":\"Address of the SpokePool contract that the user is intending to call.\"}}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"deposit(address,address,address,uint256,uint256,uint256,address,uint32,uint32,uint32,bytes)\":{\"notice\":\"Passthrough function to `depositV3()` on the SpokePool contract.\"}},\"notice\":\"SpokePoolVerifier is a contract that verifies that the SpokePool exists on this chain before sending ETH to it.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/SpokePoolVerifier.sol\":\"SpokePoolVerifier\"},\"debug\":{\"revertStrings\":\"strip\"},\"evmVersion\":\"paris\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":1000000},\"remappings\":[],\"viaIR\":true},\"sources\":{\"@openzeppelin/contracts/utils/Address.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.9.0) (utils/Address.sol)\\n\\npragma solidity ^0.8.1;\\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 * Furthermore, `isContract` will also return true if the target contract within\\n * the same transaction is already scheduled for destruction by `SELFDESTRUCT`,\\n * which only has an effect at the end of a transaction.\\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 > 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://consensys.net/diligence/blog/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.8.0/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\\n */\\n function sendValue(address payable recipient, uint256 amount) internal {\\n require(address(this).balance >= amount, \\\"Address: insufficient balance\\\");\\n\\n (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 functionCallWithValue(target, data, 0, \\\"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(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, value, \\\"Address: low-level call with value failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\\n * with `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(address(this).balance >= value, \\\"Address: insufficient balance for call\\\");\\n (bool success, bytes memory returndata) = target.call{value: value}(data);\\n return verifyCallResultFromTarget(target, 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 (bool success, bytes memory returndata) = target.staticcall(data);\\n return verifyCallResultFromTarget(target, 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 (bool success, bytes memory returndata) = target.delegatecall(data);\\n return verifyCallResultFromTarget(target, success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling\\n * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.\\n *\\n * _Available since v4.8._\\n */\\n function verifyCallResultFromTarget(\\n address target,\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n if (success) {\\n if (returndata.length == 0) {\\n // only check isContract if the call was successful and the return data is empty\\n // otherwise we already know that it was a contract\\n require(isContract(target), \\\"Address: call to non-contract\\\");\\n }\\n return returndata;\\n } else {\\n _revert(returndata, errorMessage);\\n }\\n }\\n\\n /**\\n * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the\\n * revert reason or 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 _revert(returndata, errorMessage);\\n }\\n }\\n\\n function _revert(bytes memory returndata, string memory errorMessage) private pure {\\n // Look for revert reason and bubble it up if present\\n if (returndata.length > 0) {\\n // The easiest way to bubble the revert reason is using memory via assembly\\n /// @solidity memory-safe-assembly\\n assembly {\\n let returndata_size := mload(returndata)\\n revert(add(32, returndata), returndata_size)\\n }\\n } else {\\n revert(errorMessage);\\n }\\n }\\n}\\n\",\"keccak256\":\"0x006dd67219697fe68d7fbfdea512e7c4cb64a43565ed86171d67e844982da6fa\",\"license\":\"MIT\"},\"contracts/SpokePoolVerifier.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\nimport \\\"@openzeppelin/contracts/utils/Address.sol\\\";\\nimport \\\"./interfaces/V3SpokePoolInterface.sol\\\";\\n\\n/**\\n * @notice SpokePoolVerifier is a contract that verifies that the SpokePool exists on this chain before sending ETH to it.\\n * @dev This contract must be deployed via Create2 to the same address on all chains. That way, an errant transaction sent\\n * to the wrong chain will be blocked by this contract rather than hitting a dead address. This means that this contract\\n * will not work to protect chains, like zkSync, where Create2 address derivations don't match other chains.\\n * Source: https://era.zksync.io/docs/reference/architecture/differences-with-ethereum.html#create-create2\\n * @custom:security-contact bugs@across.to\\n */\\ncontract SpokePoolVerifier {\\n using Address for address;\\n\\n /**\\n * @notice Passthrough function to `depositV3()` on the SpokePool contract.\\n * @dev Protects the caller from losing their ETH (or other native token) by reverting if the SpokePool address\\n * they intended to call does not exist on this chain. Because this contract can be deployed at the same address\\n * everywhere callers should be protected even if the transaction is submitted to an unintended network.\\n * This contract should only be used for native token deposits, as this problem only exists for native tokens.\\n * @param spokePool Address of the SpokePool contract that the user is intending to call.\\n * @param recipient Address to receive funds at on destination chain.\\n * @param inputToken Token to lock into this contract to initiate deposit.\\n * @param inputAmount Amount of tokens to deposit.\\n * @param outputAmount Amount of tokens to receive on destination chain.\\n * @param destinationChainId Denotes network where user will receive funds from SpokePool by a relayer.\\n * @param quoteTimestamp Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid\\n * to LP pool on HubPool.\\n * @param message Arbitrary data that can be used to pass additional information to the recipient along with the tokens.\\n * Note: this is intended to be used to pass along instructions for how a contract should use or allocate the tokens.\\n * @param exclusiveRelayer Address of the relayer who has exclusive rights to fill this deposit. Can be set to\\n * 0x0 if no exclusivity period is desired. If so, then must set exclusivityDeadline to 0.\\n * @param exclusivityDeadline Timestamp after which any relayer can fill this deposit. Must set\\n * to 0 if exclusiveRelayer is set to 0x0, and vice versa.\\n * @param fillDeadline Timestamp after which this deposit can no longer be filled.\\n */\\n function deposit(\\n V3SpokePoolInterface spokePool,\\n address recipient,\\n address inputToken,\\n uint256 inputAmount,\\n uint256 outputAmount,\\n uint256 destinationChainId,\\n address exclusiveRelayer,\\n uint32 quoteTimestamp,\\n uint32 fillDeadline,\\n uint32 exclusivityDeadline,\\n bytes memory message\\n ) external payable {\\n require(msg.value == inputAmount, \\\"msg.value != amount\\\");\\n require(address(spokePool).isContract(), \\\"spokePool is not a contract\\\");\\n // Set msg.sender as the depositor so that msg.sender can speed up the deposit.\\n spokePool.depositV3{ value: msg.value }(\\n msg.sender,\\n recipient,\\n inputToken,\\n // @dev Setting outputToken to 0x0 to instruct fillers to use the equivalent token\\n // as the originToken on the destination chain.\\n address(0),\\n inputAmount,\\n outputAmount,\\n destinationChainId,\\n exclusiveRelayer,\\n quoteTimestamp,\\n fillDeadline,\\n exclusivityDeadline,\\n message\\n );\\n }\\n}\\n\",\"keccak256\":\"0xd5b1ec1b7048634a8b0a7e1e2c68ce51e410157b14778a207b64aff49bc5c6f0\",\"license\":\"BUSL-1.1\"},\"contracts/interfaces/V3SpokePoolInterface.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\n// Contains structs and functions used by SpokePool contracts to facilitate universal settlement.\\ninterface V3SpokePoolInterface {\\n /**************************************\\n * ENUMS *\\n **************************************/\\n\\n // Fill status tracks on-chain state of deposit, uniquely identified by relayHash.\\n enum FillStatus {\\n Unfilled,\\n RequestedSlowFill,\\n Filled\\n }\\n // Fill type is emitted in the FilledRelay event to assist Dataworker with determining which types of\\n // fills to refund (e.g. only fast fills) and whether a fast fill created a sow fill excess.\\n enum FillType {\\n FastFill,\\n // Fast fills are normal fills that do not replace a slow fill request.\\n ReplacedSlowFill,\\n // Replaced slow fills are fast fills that replace a slow fill request. This type is used by the Dataworker\\n // to know when to send excess funds from the SpokePool to the HubPool because they can no longer be used\\n // for a slow fill execution.\\n SlowFill\\n // Slow fills are requested via requestSlowFill and executed by executeSlowRelayLeaf after a bundle containing\\n // the slow fill is validated.\\n }\\n\\n /**************************************\\n * STRUCTS *\\n **************************************/\\n\\n // This struct represents the data to fully specify a **unique** relay submitted on this chain.\\n // This data is hashed with the chainId() and saved by the SpokePool to prevent collisions and protect against\\n // replay attacks on other chains. If any portion of this data differs, the relay is considered to be\\n // completely distinct.\\n struct V3RelayData {\\n // The address that made the deposit on the origin chain.\\n address depositor;\\n // The recipient address on the destination chain.\\n address recipient;\\n // This is the exclusive relayer who can fill the deposit before the exclusivity deadline.\\n address exclusiveRelayer;\\n // Token that is deposited on origin chain by depositor.\\n address inputToken;\\n // Token that is received on destination chain by recipient.\\n address outputToken;\\n // The amount of input token deposited by depositor.\\n uint256 inputAmount;\\n // The amount of output token to be received by recipient.\\n uint256 outputAmount;\\n // Origin chain id.\\n uint256 originChainId;\\n // The id uniquely identifying this deposit on the origin chain.\\n uint32 depositId;\\n // The timestamp on the destination chain after which this deposit can no longer be filled.\\n uint32 fillDeadline;\\n // The timestamp on the destination chain after which any relayer can fill the deposit.\\n uint32 exclusivityDeadline;\\n // Data that is forwarded to the recipient.\\n bytes message;\\n }\\n\\n // Contains parameters passed in by someone who wants to execute a slow relay leaf.\\n struct V3SlowFill {\\n V3RelayData relayData;\\n uint256 chainId;\\n uint256 updatedOutputAmount;\\n }\\n\\n // Contains information about a relay to be sent along with additional information that is not unique to the\\n // relay itself but is required to know how to process the relay. For example, \\\"updatedX\\\" fields can be used\\n // by the relayer to modify fields of the relay with the depositor's permission, and \\\"repaymentChainId\\\" is specified\\n // by the relayer to determine where to take a relayer refund, but doesn't affect the uniqueness of the relay.\\n struct V3RelayExecutionParams {\\n V3RelayData relay;\\n bytes32 relayHash;\\n uint256 updatedOutputAmount;\\n address updatedRecipient;\\n bytes updatedMessage;\\n uint256 repaymentChainId;\\n }\\n\\n // Packs together parameters emitted in FilledV3Relay because there are too many emitted otherwise.\\n // Similar to V3RelayExecutionParams, these parameters are not used to uniquely identify the deposit being\\n // filled so they don't have to be unpacked by all clients.\\n struct V3RelayExecutionEventInfo {\\n address updatedRecipient;\\n bytes updatedMessage;\\n uint256 updatedOutputAmount;\\n FillType fillType;\\n }\\n\\n /**************************************\\n * EVENTS *\\n **************************************/\\n\\n event V3FundsDeposited(\\n address inputToken,\\n address outputToken,\\n uint256 inputAmount,\\n uint256 outputAmount,\\n uint256 indexed destinationChainId,\\n uint32 indexed depositId,\\n uint32 quoteTimestamp,\\n uint32 fillDeadline,\\n uint32 exclusivityDeadline,\\n address indexed depositor,\\n address recipient,\\n address exclusiveRelayer,\\n bytes message\\n );\\n\\n event RequestedSpeedUpV3Deposit(\\n uint256 updatedOutputAmount,\\n uint32 indexed depositId,\\n address indexed depositor,\\n address updatedRecipient,\\n bytes updatedMessage,\\n bytes depositorSignature\\n );\\n\\n event FilledV3Relay(\\n address inputToken,\\n address outputToken,\\n uint256 inputAmount,\\n uint256 outputAmount,\\n uint256 repaymentChainId,\\n uint256 indexed originChainId,\\n uint32 indexed depositId,\\n uint32 fillDeadline,\\n uint32 exclusivityDeadline,\\n address exclusiveRelayer,\\n address indexed relayer,\\n address depositor,\\n address recipient,\\n bytes message,\\n V3RelayExecutionEventInfo relayExecutionInfo\\n );\\n\\n event RequestedV3SlowFill(\\n address inputToken,\\n address outputToken,\\n uint256 inputAmount,\\n uint256 outputAmount,\\n uint256 indexed originChainId,\\n uint32 indexed depositId,\\n uint32 fillDeadline,\\n uint32 exclusivityDeadline,\\n address exclusiveRelayer,\\n address depositor,\\n address recipient,\\n bytes message\\n );\\n\\n /**************************************\\n * FUNCTIONS *\\n **************************************/\\n\\n function depositV3(\\n address depositor,\\n address recipient,\\n address inputToken,\\n address outputToken,\\n uint256 inputAmount,\\n uint256 outputAmount,\\n uint256 destinationChainId,\\n address exclusiveRelayer,\\n uint32 quoteTimestamp,\\n uint32 fillDeadline,\\n uint32 exclusivityDeadline,\\n bytes calldata message\\n ) external payable;\\n\\n function depositV3Now(\\n address depositor,\\n address recipient,\\n address inputToken,\\n address outputToken,\\n uint256 inputAmount,\\n uint256 outputAmount,\\n uint256 destinationChainId,\\n address exclusiveRelayer,\\n uint32 fillDeadlineOffset,\\n uint32 exclusivityDeadline,\\n bytes calldata message\\n ) external payable;\\n\\n function speedUpV3Deposit(\\n address depositor,\\n uint32 depositId,\\n uint256 updatedOutputAmount,\\n address updatedRecipient,\\n bytes calldata updatedMessage,\\n bytes calldata depositorSignature\\n ) external;\\n\\n function fillV3Relay(V3RelayData calldata relayData, uint256 repaymentChainId) external;\\n\\n function fillV3RelayWithUpdatedDeposit(\\n V3RelayData calldata relayData,\\n uint256 repaymentChainId,\\n uint256 updatedOutputAmount,\\n address updatedRecipient,\\n bytes calldata updatedMessage,\\n bytes calldata depositorSignature\\n ) external;\\n\\n function requestV3SlowFill(V3RelayData calldata relayData) external;\\n\\n function executeV3SlowRelayLeaf(\\n V3SlowFill calldata slowFillLeaf,\\n uint32 rootBundleId,\\n bytes32[] calldata proof\\n ) external;\\n\\n /**************************************\\n * ERRORS *\\n **************************************/\\n\\n error DisabledRoute();\\n error InvalidQuoteTimestamp();\\n error InvalidFillDeadline();\\n error InvalidExclusiveRelayer();\\n error InvalidExclusivityDeadline();\\n error MsgValueDoesNotMatchInputAmount();\\n error NotExclusiveRelayer();\\n error NoSlowFillsInExclusivityWindow();\\n error RelayFilled();\\n error InvalidSlowFillRequest();\\n error ExpiredFillDeadline();\\n error InvalidMerkleProof();\\n error InvalidChainId();\\n error InvalidMerkleLeaf();\\n error ClaimedMerkleLeaf();\\n error InvalidPayoutAdjustmentPct();\\n}\\n\",\"keccak256\":\"0x374b7e9cb8afbcaec69cdbcde480676b5d927db84c7f38221331d1226af68d9d\",\"license\":\"BUSL-1.1\"}},\"version\":1}", + "bytecode": "0x60808060405234610016576103a4908161001c8239f35b600080fdfe600436101561000d57600080fd5b6000803560e01c63902e949c1461002357600080fd5b6101607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261036b5773ffffffffffffffffffffffffffffffffffffffff6004358181168103610367576024359082821682036103635760443591838316830361035f5760c435848116810361035b5760e4359063ffffffff928383168303610357576101043590848216820361035357610124359385851685036103225767ffffffffffffffff610144351161032257366023610144350112156103225767ffffffffffffffff6101443560040135116103265767ffffffffffffffff6004610144350135601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f0116608090810191821191101761032657608060046101443590810135601f81017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f011683016040529182905236910160240111610322576101443560048101359060240160a03760a06004610144350135018a90526064353403610322578887163b15610322578887163b1561032257918589979593888296818e9c60409e9b979e519e8f9d8e917f7b9392320000000000000000000000000000000000000000000000000000000083523360048401521690602401521660448c01528b60648c015260643560848c015260843560a48c015260a43560c48c01521660e48a01521661010488015216610124860152166101448401526101648301610180905260805180610184850152845b8181106103075750908391827fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f6101a49389858286010152011681010301923491165af180156102fc576102ba575080f35b67ffffffffffffffff81116102cf5760405280f35b6024827f4e487b710000000000000000000000000000000000000000000000000000000081526041600452fd5b6040513d84823e3d90fd5b60a08101518782016101a40152879550869450602001610266565b8980fd5b60248a7f4e487b710000000000000000000000000000000000000000000000000000000081526041600452fd5b8880fd5b8780fd5b8580fd5b8480fd5b8380fd5b8280fd5b80fdfea26469706673582212201ceff237e6adbd0d3f92e892f7f3f51306c23eac5f7e3f896c2c723d9e5be3a664736f6c63430008130033", + "deployedBytecode": "0x600436101561000d57600080fd5b6000803560e01c63902e949c1461002357600080fd5b6101607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261036b5773ffffffffffffffffffffffffffffffffffffffff6004358181168103610367576024359082821682036103635760443591838316830361035f5760c435848116810361035b5760e4359063ffffffff928383168303610357576101043590848216820361035357610124359385851685036103225767ffffffffffffffff610144351161032257366023610144350112156103225767ffffffffffffffff6101443560040135116103265767ffffffffffffffff6004610144350135601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f0116608090810191821191101761032657608060046101443590810135601f81017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f011683016040529182905236910160240111610322576101443560048101359060240160a03760a06004610144350135018a90526064353403610322578887163b15610322578887163b1561032257918589979593888296818e9c60409e9b979e519e8f9d8e917f7b9392320000000000000000000000000000000000000000000000000000000083523360048401521690602401521660448c01528b60648c015260643560848c015260843560a48c015260a43560c48c01521660e48a01521661010488015216610124860152166101448401526101648301610180905260805180610184850152845b8181106103075750908391827fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f6101a49389858286010152011681010301923491165af180156102fc576102ba575080f35b67ffffffffffffffff81116102cf5760405280f35b6024827f4e487b710000000000000000000000000000000000000000000000000000000081526041600452fd5b6040513d84823e3d90fd5b60a08101518782016101a40152879550869450602001610266565b8980fd5b60248a7f4e487b710000000000000000000000000000000000000000000000000000000081526041600452fd5b8880fd5b8780fd5b8580fd5b8480fd5b8380fd5b8280fd5b80fdfea26469706673582212201ceff237e6adbd0d3f92e892f7f3f51306c23eac5f7e3f896c2c723d9e5be3a664736f6c63430008130033", "devdoc": { + "custom:security-contact": "bugs@across.to", "details": "This contract must be deployed via Create2 to the same address on all chains. That way, an errant transaction sent to the wrong chain will be blocked by this contract rather than hitting a dead address. This means that this contract will not work to protect chains, like zkSync, where Create2 address derivations don't match other chains. Source: https://era.zksync.io/docs/reference/architecture/differences-with-ethereum.html#create-create2", "kind": "dev", "methods": { - "deposit(address,address,address,uint256,uint256,int64,uint32,bytes,uint256)": { + "deposit(address,address,address,uint256,uint256,uint256,address,uint32,uint32,uint32,bytes)": { "details": "Protects the caller from losing their ETH (or other native token) by reverting if the SpokePool address they intended to call does not exist on this chain. Because this contract can be deployed at the same address everywhere callers should be protected even if the transaction is submitted to an unintended network. This contract should only be used for native token deposits, as this problem only exists for native tokens.", "params": { - "amount": "Amount of tokens to deposit. Will be amount of tokens to receive less fees.", "destinationChainId": "Denotes network where user will receive funds from SpokePool by a relayer.", - "maxCount": "used to protect the depositor from frontrunning to guarantee their quote remains valid. Note: this is intended to be used to pass along instructions for how a contract should use or allocate the tokens.", + "exclusiveRelayer": "Address of the relayer who has exclusive rights to fill this deposit. Can be set to 0x0 if no exclusivity period is desired. If so, then must set exclusivityDeadline to 0.", + "exclusivityDeadline": "Timestamp after which any relayer can fill this deposit. Must set to 0 if exclusiveRelayer is set to 0x0, and vice versa.", + "fillDeadline": "Timestamp after which this deposit can no longer be filled.", + "inputAmount": "Amount of tokens to deposit.", + "inputToken": "Token to lock into this contract to initiate deposit.", "message": "Arbitrary data that can be used to pass additional information to the recipient along with the tokens. Note: this is intended to be used to pass along instructions for how a contract should use or allocate the tokens.", - "originToken": "Token to lock into this contract to initiate deposit.", + "outputAmount": "Amount of tokens to receive on destination chain.", "quoteTimestamp": "Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid to LP pool on HubPool.", "recipient": "Address to receive funds at on destination chain.", - "relayerFeePct": "% of deposit amount taken out to incentivize a fast relayer.", "spokePool": "Address of the SpokePool contract that the user is intending to call." } } @@ -101,7 +114,7 @@ "userdoc": { "kind": "user", "methods": { - "deposit(address,address,address,uint256,uint256,int64,uint32,bytes,uint256)": { + "deposit(address,address,address,uint256,uint256,uint256,address,uint32,uint32,uint32,bytes)": { "notice": "Passthrough function to `depositV3()` on the SpokePool contract." } }, diff --git a/deployments/arbitrum/solcInputs/1a67233dfe969c05446730f26ab1d2c8.json b/deployments/arbitrum/solcInputs/1a67233dfe969c05446730f26ab1d2c8.json new file mode 100644 index 000000000..96daeb1aa --- /dev/null +++ b/deployments/arbitrum/solcInputs/1a67233dfe969c05446730f26ab1d2c8.json @@ -0,0 +1,43 @@ +{ + "language": "Solidity", + "sources": { + "@openzeppelin/contracts/utils/Address.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (utils/Address.sol)\n\npragma solidity ^0.8.1;\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 * Furthermore, `isContract` will also return true if the target contract within\n * the same transaction is already scheduled for destruction by `SELFDESTRUCT`,\n * which only has an effect at the end of a transaction.\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 > 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://consensys.net/diligence/blog/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.8.0/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n require(address(this).balance >= amount, \"Address: insufficient balance\");\n\n (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 functionCallWithValue(target, data, 0, \"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(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n return functionCallWithValue(target, data, value, \"Address: low-level call with value failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\n * with `errorMessage` as a fallback revert reason when `target` reverts.\n *\n * _Available since v3.1._\n */\n function functionCallWithValue(\n address target,\n bytes memory data,\n uint256 value,\n string memory errorMessage\n ) internal returns (bytes memory) {\n require(address(this).balance >= value, \"Address: insufficient balance for call\");\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, 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 (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, 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 (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata, errorMessage);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling\n * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.\n *\n * _Available since v4.8._\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata,\n string memory errorMessage\n ) internal view returns (bytes memory) {\n if (success) {\n if (returndata.length == 0) {\n // only check isContract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n require(isContract(target), \"Address: call to non-contract\");\n }\n return returndata;\n } else {\n _revert(returndata, errorMessage);\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the\n * revert reason or 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 _revert(returndata, errorMessage);\n }\n }\n\n function _revert(bytes memory returndata, string memory errorMessage) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length > 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert(errorMessage);\n }\n }\n}\n" + }, + "contracts/interfaces/V3SpokePoolInterface.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n// Contains structs and functions used by SpokePool contracts to facilitate universal settlement.\ninterface V3SpokePoolInterface {\n /**************************************\n * ENUMS *\n **************************************/\n\n // Fill status tracks on-chain state of deposit, uniquely identified by relayHash.\n enum FillStatus {\n Unfilled,\n RequestedSlowFill,\n Filled\n }\n // Fill type is emitted in the FilledRelay event to assist Dataworker with determining which types of\n // fills to refund (e.g. only fast fills) and whether a fast fill created a sow fill excess.\n enum FillType {\n FastFill,\n // Fast fills are normal fills that do not replace a slow fill request.\n ReplacedSlowFill,\n // Replaced slow fills are fast fills that replace a slow fill request. This type is used by the Dataworker\n // to know when to send excess funds from the SpokePool to the HubPool because they can no longer be used\n // for a slow fill execution.\n SlowFill\n // Slow fills are requested via requestSlowFill and executed by executeSlowRelayLeaf after a bundle containing\n // the slow fill is validated.\n }\n\n /**************************************\n * STRUCTS *\n **************************************/\n\n // This struct represents the data to fully specify a **unique** relay submitted on this chain.\n // This data is hashed with the chainId() and saved by the SpokePool to prevent collisions and protect against\n // replay attacks on other chains. If any portion of this data differs, the relay is considered to be\n // completely distinct.\n struct V3RelayData {\n // The address that made the deposit on the origin chain.\n address depositor;\n // The recipient address on the destination chain.\n address recipient;\n // This is the exclusive relayer who can fill the deposit before the exclusivity deadline.\n address exclusiveRelayer;\n // Token that is deposited on origin chain by depositor.\n address inputToken;\n // Token that is received on destination chain by recipient.\n address outputToken;\n // The amount of input token deposited by depositor.\n uint256 inputAmount;\n // The amount of output token to be received by recipient.\n uint256 outputAmount;\n // Origin chain id.\n uint256 originChainId;\n // The id uniquely identifying this deposit on the origin chain.\n uint32 depositId;\n // The timestamp on the destination chain after which this deposit can no longer be filled.\n uint32 fillDeadline;\n // The timestamp on the destination chain after which any relayer can fill the deposit.\n uint32 exclusivityDeadline;\n // Data that is forwarded to the recipient.\n bytes message;\n }\n\n // Contains parameters passed in by someone who wants to execute a slow relay leaf.\n struct V3SlowFill {\n V3RelayData relayData;\n uint256 chainId;\n uint256 updatedOutputAmount;\n }\n\n // Contains information about a relay to be sent along with additional information that is not unique to the\n // relay itself but is required to know how to process the relay. For example, \"updatedX\" fields can be used\n // by the relayer to modify fields of the relay with the depositor's permission, and \"repaymentChainId\" is specified\n // by the relayer to determine where to take a relayer refund, but doesn't affect the uniqueness of the relay.\n struct V3RelayExecutionParams {\n V3RelayData relay;\n bytes32 relayHash;\n uint256 updatedOutputAmount;\n address updatedRecipient;\n bytes updatedMessage;\n uint256 repaymentChainId;\n }\n\n // Packs together parameters emitted in FilledV3Relay because there are too many emitted otherwise.\n // Similar to V3RelayExecutionParams, these parameters are not used to uniquely identify the deposit being\n // filled so they don't have to be unpacked by all clients.\n struct V3RelayExecutionEventInfo {\n address updatedRecipient;\n bytes updatedMessage;\n uint256 updatedOutputAmount;\n FillType fillType;\n }\n\n /**************************************\n * EVENTS *\n **************************************/\n\n event V3FundsDeposited(\n address inputToken,\n address outputToken,\n uint256 inputAmount,\n uint256 outputAmount,\n uint256 indexed destinationChainId,\n uint32 indexed depositId,\n uint32 quoteTimestamp,\n uint32 fillDeadline,\n uint32 exclusivityDeadline,\n address indexed depositor,\n address recipient,\n address exclusiveRelayer,\n bytes message\n );\n\n event RequestedSpeedUpV3Deposit(\n uint256 updatedOutputAmount,\n uint32 indexed depositId,\n address indexed depositor,\n address updatedRecipient,\n bytes updatedMessage,\n bytes depositorSignature\n );\n\n event FilledV3Relay(\n address inputToken,\n address outputToken,\n uint256 inputAmount,\n uint256 outputAmount,\n uint256 repaymentChainId,\n uint256 indexed originChainId,\n uint32 indexed depositId,\n uint32 fillDeadline,\n uint32 exclusivityDeadline,\n address exclusiveRelayer,\n address indexed relayer,\n address depositor,\n address recipient,\n bytes message,\n V3RelayExecutionEventInfo relayExecutionInfo\n );\n\n event RequestedV3SlowFill(\n address inputToken,\n address outputToken,\n uint256 inputAmount,\n uint256 outputAmount,\n uint256 indexed originChainId,\n uint32 indexed depositId,\n uint32 fillDeadline,\n uint32 exclusivityDeadline,\n address exclusiveRelayer,\n address depositor,\n address recipient,\n bytes message\n );\n\n /**************************************\n * FUNCTIONS *\n **************************************/\n\n function depositV3(\n address depositor,\n address recipient,\n address inputToken,\n address outputToken,\n uint256 inputAmount,\n uint256 outputAmount,\n uint256 destinationChainId,\n address exclusiveRelayer,\n uint32 quoteTimestamp,\n uint32 fillDeadline,\n uint32 exclusivityDeadline,\n bytes calldata message\n ) external payable;\n\n function depositV3Now(\n address depositor,\n address recipient,\n address inputToken,\n address outputToken,\n uint256 inputAmount,\n uint256 outputAmount,\n uint256 destinationChainId,\n address exclusiveRelayer,\n uint32 fillDeadlineOffset,\n uint32 exclusivityDeadline,\n bytes calldata message\n ) external payable;\n\n function speedUpV3Deposit(\n address depositor,\n uint32 depositId,\n uint256 updatedOutputAmount,\n address updatedRecipient,\n bytes calldata updatedMessage,\n bytes calldata depositorSignature\n ) external;\n\n function fillV3Relay(V3RelayData calldata relayData, uint256 repaymentChainId) external;\n\n function fillV3RelayWithUpdatedDeposit(\n V3RelayData calldata relayData,\n uint256 repaymentChainId,\n uint256 updatedOutputAmount,\n address updatedRecipient,\n bytes calldata updatedMessage,\n bytes calldata depositorSignature\n ) external;\n\n function requestV3SlowFill(V3RelayData calldata relayData) external;\n\n function executeV3SlowRelayLeaf(\n V3SlowFill calldata slowFillLeaf,\n uint32 rootBundleId,\n bytes32[] calldata proof\n ) external;\n\n /**************************************\n * ERRORS *\n **************************************/\n\n error DisabledRoute();\n error InvalidQuoteTimestamp();\n error InvalidFillDeadline();\n error InvalidExclusiveRelayer();\n error InvalidExclusivityDeadline();\n error MsgValueDoesNotMatchInputAmount();\n error NotExclusiveRelayer();\n error NoSlowFillsInExclusivityWindow();\n error RelayFilled();\n error InvalidSlowFillRequest();\n error ExpiredFillDeadline();\n error InvalidMerkleProof();\n error InvalidChainId();\n error InvalidMerkleLeaf();\n error ClaimedMerkleLeaf();\n error InvalidPayoutAdjustmentPct();\n}\n" + }, + "contracts/SpokePoolVerifier.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/utils/Address.sol\";\nimport \"./interfaces/V3SpokePoolInterface.sol\";\n\n/**\n * @notice SpokePoolVerifier is a contract that verifies that the SpokePool exists on this chain before sending ETH to it.\n * @dev This contract must be deployed via Create2 to the same address on all chains. That way, an errant transaction sent\n * to the wrong chain will be blocked by this contract rather than hitting a dead address. This means that this contract\n * will not work to protect chains, like zkSync, where Create2 address derivations don't match other chains.\n * Source: https://era.zksync.io/docs/reference/architecture/differences-with-ethereum.html#create-create2\n * @custom:security-contact bugs@across.to\n */\ncontract SpokePoolVerifier {\n using Address for address;\n\n /**\n * @notice Passthrough function to `depositV3()` on the SpokePool contract.\n * @dev Protects the caller from losing their ETH (or other native token) by reverting if the SpokePool address\n * they intended to call does not exist on this chain. Because this contract can be deployed at the same address\n * everywhere callers should be protected even if the transaction is submitted to an unintended network.\n * This contract should only be used for native token deposits, as this problem only exists for native tokens.\n * @param spokePool Address of the SpokePool contract that the user is intending to call.\n * @param recipient Address to receive funds at on destination chain.\n * @param inputToken Token to lock into this contract to initiate deposit.\n * @param inputAmount Amount of tokens to deposit.\n * @param outputAmount Amount of tokens to receive on destination chain.\n * @param destinationChainId Denotes network where user will receive funds from SpokePool by a relayer.\n * @param quoteTimestamp Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid\n * to LP pool on HubPool.\n * @param message Arbitrary data that can be used to pass additional information to the recipient along with the tokens.\n * Note: this is intended to be used to pass along instructions for how a contract should use or allocate the tokens.\n * @param exclusiveRelayer Address of the relayer who has exclusive rights to fill this deposit. Can be set to\n * 0x0 if no exclusivity period is desired. If so, then must set exclusivityDeadline to 0.\n * @param exclusivityDeadline Timestamp after which any relayer can fill this deposit. Must set\n * to 0 if exclusiveRelayer is set to 0x0, and vice versa.\n * @param fillDeadline Timestamp after which this deposit can no longer be filled.\n */\n function deposit(\n V3SpokePoolInterface spokePool,\n address recipient,\n address inputToken,\n uint256 inputAmount,\n uint256 outputAmount,\n uint256 destinationChainId,\n uint32 quoteTimestamp,\n bytes memory message,\n address exclusiveRelayer,\n uint32 exclusivityDeadline,\n uint32 fillDeadline\n ) external payable {\n require(msg.value == inputAmount, \"msg.value != amount\");\n require(address(spokePool).isContract(), \"spokePool is not a contract\");\n // Set msg.sender as the depositor so that msg.sender can speed up the deposit.\n spokePool.depositV3{ value: msg.value }(\n msg.sender,\n recipient,\n inputToken,\n // @dev Setting outputToken to 0x0 to instruct fillers to use the equivalent token\n // as the originToken on the destination chain.\n address(0),\n inputAmount,\n outputAmount,\n destinationChainId,\n exclusiveRelayer,\n quoteTimestamp,\n fillDeadline,\n exclusivityDeadline,\n message\n );\n }\n}\n" + } + }, + "settings": { + "optimizer": { + "enabled": true, + "runs": 1000000 + }, + "viaIR": true, + "debug": { + "revertStrings": "strip" + }, + "outputSelection": { + "*": { + "*": [ + "abi", + "evm.bytecode", + "evm.deployedBytecode", + "evm.methodIdentifiers", + "metadata", + "devdoc", + "userdoc", + "storageLayout", + "evm.gasEstimates" + ], + "": ["ast"] + } + }, + "metadata": { + "useLiteralContent": true + } + } +} diff --git a/deployments/arbitrum/solcInputs/783274f805324492b21545b62eb0dbfe.json b/deployments/arbitrum/solcInputs/783274f805324492b21545b62eb0dbfe.json new file mode 100644 index 000000000..4bcffc07b --- /dev/null +++ b/deployments/arbitrum/solcInputs/783274f805324492b21545b62eb0dbfe.json @@ -0,0 +1,43 @@ +{ + "language": "Solidity", + "sources": { + "@openzeppelin/contracts/utils/Address.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (utils/Address.sol)\n\npragma solidity ^0.8.1;\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 * Furthermore, `isContract` will also return true if the target contract within\n * the same transaction is already scheduled for destruction by `SELFDESTRUCT`,\n * which only has an effect at the end of a transaction.\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 > 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://consensys.net/diligence/blog/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.8.0/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n require(address(this).balance >= amount, \"Address: insufficient balance\");\n\n (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 functionCallWithValue(target, data, 0, \"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(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n return functionCallWithValue(target, data, value, \"Address: low-level call with value failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\n * with `errorMessage` as a fallback revert reason when `target` reverts.\n *\n * _Available since v3.1._\n */\n function functionCallWithValue(\n address target,\n bytes memory data,\n uint256 value,\n string memory errorMessage\n ) internal returns (bytes memory) {\n require(address(this).balance >= value, \"Address: insufficient balance for call\");\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, 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 (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, 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 (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata, errorMessage);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling\n * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.\n *\n * _Available since v4.8._\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata,\n string memory errorMessage\n ) internal view returns (bytes memory) {\n if (success) {\n if (returndata.length == 0) {\n // only check isContract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n require(isContract(target), \"Address: call to non-contract\");\n }\n return returndata;\n } else {\n _revert(returndata, errorMessage);\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the\n * revert reason or 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 _revert(returndata, errorMessage);\n }\n }\n\n function _revert(bytes memory returndata, string memory errorMessage) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length > 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert(errorMessage);\n }\n }\n}\n" + }, + "contracts/interfaces/V3SpokePoolInterface.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n// Contains structs and functions used by SpokePool contracts to facilitate universal settlement.\ninterface V3SpokePoolInterface {\n /**************************************\n * ENUMS *\n **************************************/\n\n // Fill status tracks on-chain state of deposit, uniquely identified by relayHash.\n enum FillStatus {\n Unfilled,\n RequestedSlowFill,\n Filled\n }\n // Fill type is emitted in the FilledRelay event to assist Dataworker with determining which types of\n // fills to refund (e.g. only fast fills) and whether a fast fill created a sow fill excess.\n enum FillType {\n FastFill,\n // Fast fills are normal fills that do not replace a slow fill request.\n ReplacedSlowFill,\n // Replaced slow fills are fast fills that replace a slow fill request. This type is used by the Dataworker\n // to know when to send excess funds from the SpokePool to the HubPool because they can no longer be used\n // for a slow fill execution.\n SlowFill\n // Slow fills are requested via requestSlowFill and executed by executeSlowRelayLeaf after a bundle containing\n // the slow fill is validated.\n }\n\n /**************************************\n * STRUCTS *\n **************************************/\n\n // This struct represents the data to fully specify a **unique** relay submitted on this chain.\n // This data is hashed with the chainId() and saved by the SpokePool to prevent collisions and protect against\n // replay attacks on other chains. If any portion of this data differs, the relay is considered to be\n // completely distinct.\n struct V3RelayData {\n // The address that made the deposit on the origin chain.\n address depositor;\n // The recipient address on the destination chain.\n address recipient;\n // This is the exclusive relayer who can fill the deposit before the exclusivity deadline.\n address exclusiveRelayer;\n // Token that is deposited on origin chain by depositor.\n address inputToken;\n // Token that is received on destination chain by recipient.\n address outputToken;\n // The amount of input token deposited by depositor.\n uint256 inputAmount;\n // The amount of output token to be received by recipient.\n uint256 outputAmount;\n // Origin chain id.\n uint256 originChainId;\n // The id uniquely identifying this deposit on the origin chain.\n uint32 depositId;\n // The timestamp on the destination chain after which this deposit can no longer be filled.\n uint32 fillDeadline;\n // The timestamp on the destination chain after which any relayer can fill the deposit.\n uint32 exclusivityDeadline;\n // Data that is forwarded to the recipient.\n bytes message;\n }\n\n // Contains parameters passed in by someone who wants to execute a slow relay leaf.\n struct V3SlowFill {\n V3RelayData relayData;\n uint256 chainId;\n uint256 updatedOutputAmount;\n }\n\n // Contains information about a relay to be sent along with additional information that is not unique to the\n // relay itself but is required to know how to process the relay. For example, \"updatedX\" fields can be used\n // by the relayer to modify fields of the relay with the depositor's permission, and \"repaymentChainId\" is specified\n // by the relayer to determine where to take a relayer refund, but doesn't affect the uniqueness of the relay.\n struct V3RelayExecutionParams {\n V3RelayData relay;\n bytes32 relayHash;\n uint256 updatedOutputAmount;\n address updatedRecipient;\n bytes updatedMessage;\n uint256 repaymentChainId;\n }\n\n // Packs together parameters emitted in FilledV3Relay because there are too many emitted otherwise.\n // Similar to V3RelayExecutionParams, these parameters are not used to uniquely identify the deposit being\n // filled so they don't have to be unpacked by all clients.\n struct V3RelayExecutionEventInfo {\n address updatedRecipient;\n bytes updatedMessage;\n uint256 updatedOutputAmount;\n FillType fillType;\n }\n\n /**************************************\n * EVENTS *\n **************************************/\n\n event V3FundsDeposited(\n address inputToken,\n address outputToken,\n uint256 inputAmount,\n uint256 outputAmount,\n uint256 indexed destinationChainId,\n uint32 indexed depositId,\n uint32 quoteTimestamp,\n uint32 fillDeadline,\n uint32 exclusivityDeadline,\n address indexed depositor,\n address recipient,\n address exclusiveRelayer,\n bytes message\n );\n\n event RequestedSpeedUpV3Deposit(\n uint256 updatedOutputAmount,\n uint32 indexed depositId,\n address indexed depositor,\n address updatedRecipient,\n bytes updatedMessage,\n bytes depositorSignature\n );\n\n event FilledV3Relay(\n address inputToken,\n address outputToken,\n uint256 inputAmount,\n uint256 outputAmount,\n uint256 repaymentChainId,\n uint256 indexed originChainId,\n uint32 indexed depositId,\n uint32 fillDeadline,\n uint32 exclusivityDeadline,\n address exclusiveRelayer,\n address indexed relayer,\n address depositor,\n address recipient,\n bytes message,\n V3RelayExecutionEventInfo relayExecutionInfo\n );\n\n event RequestedV3SlowFill(\n address inputToken,\n address outputToken,\n uint256 inputAmount,\n uint256 outputAmount,\n uint256 indexed originChainId,\n uint32 indexed depositId,\n uint32 fillDeadline,\n uint32 exclusivityDeadline,\n address exclusiveRelayer,\n address depositor,\n address recipient,\n bytes message\n );\n\n /**************************************\n * FUNCTIONS *\n **************************************/\n\n function depositV3(\n address depositor,\n address recipient,\n address inputToken,\n address outputToken,\n uint256 inputAmount,\n uint256 outputAmount,\n uint256 destinationChainId,\n address exclusiveRelayer,\n uint32 quoteTimestamp,\n uint32 fillDeadline,\n uint32 exclusivityDeadline,\n bytes calldata message\n ) external payable;\n\n function depositV3Now(\n address depositor,\n address recipient,\n address inputToken,\n address outputToken,\n uint256 inputAmount,\n uint256 outputAmount,\n uint256 destinationChainId,\n address exclusiveRelayer,\n uint32 fillDeadlineOffset,\n uint32 exclusivityDeadline,\n bytes calldata message\n ) external payable;\n\n function speedUpV3Deposit(\n address depositor,\n uint32 depositId,\n uint256 updatedOutputAmount,\n address updatedRecipient,\n bytes calldata updatedMessage,\n bytes calldata depositorSignature\n ) external;\n\n function fillV3Relay(V3RelayData calldata relayData, uint256 repaymentChainId) external;\n\n function fillV3RelayWithUpdatedDeposit(\n V3RelayData calldata relayData,\n uint256 repaymentChainId,\n uint256 updatedOutputAmount,\n address updatedRecipient,\n bytes calldata updatedMessage,\n bytes calldata depositorSignature\n ) external;\n\n function requestV3SlowFill(V3RelayData calldata relayData) external;\n\n function executeV3SlowRelayLeaf(\n V3SlowFill calldata slowFillLeaf,\n uint32 rootBundleId,\n bytes32[] calldata proof\n ) external;\n\n /**************************************\n * ERRORS *\n **************************************/\n\n error DisabledRoute();\n error InvalidQuoteTimestamp();\n error InvalidFillDeadline();\n error InvalidExclusiveRelayer();\n error InvalidExclusivityDeadline();\n error MsgValueDoesNotMatchInputAmount();\n error NotExclusiveRelayer();\n error NoSlowFillsInExclusivityWindow();\n error RelayFilled();\n error InvalidSlowFillRequest();\n error ExpiredFillDeadline();\n error InvalidMerkleProof();\n error InvalidChainId();\n error InvalidMerkleLeaf();\n error ClaimedMerkleLeaf();\n error InvalidPayoutAdjustmentPct();\n}\n" + }, + "contracts/SpokePoolVerifier.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/utils/Address.sol\";\nimport \"./interfaces/V3SpokePoolInterface.sol\";\n\n/**\n * @notice SpokePoolVerifier is a contract that verifies that the SpokePool exists on this chain before sending ETH to it.\n * @dev This contract must be deployed via Create2 to the same address on all chains. That way, an errant transaction sent\n * to the wrong chain will be blocked by this contract rather than hitting a dead address. This means that this contract\n * will not work to protect chains, like zkSync, where Create2 address derivations don't match other chains.\n * Source: https://era.zksync.io/docs/reference/architecture/differences-with-ethereum.html#create-create2\n * @custom:security-contact bugs@across.to\n */\ncontract SpokePoolVerifier {\n using Address for address;\n\n /**\n * @notice Passthrough function to `depositV3()` on the SpokePool contract.\n * @dev Protects the caller from losing their ETH (or other native token) by reverting if the SpokePool address\n * they intended to call does not exist on this chain. Because this contract can be deployed at the same address\n * everywhere callers should be protected even if the transaction is submitted to an unintended network.\n * This contract should only be used for native token deposits, as this problem only exists for native tokens.\n * @param spokePool Address of the SpokePool contract that the user is intending to call.\n * @param recipient Address to receive funds at on destination chain.\n * @param inputToken Token to lock into this contract to initiate deposit.\n * @param inputAmount Amount of tokens to deposit.\n * @param outputAmount Amount of tokens to receive on destination chain.\n * @param destinationChainId Denotes network where user will receive funds from SpokePool by a relayer.\n * @param quoteTimestamp Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid\n * to LP pool on HubPool.\n * @param message Arbitrary data that can be used to pass additional information to the recipient along with the tokens.\n * Note: this is intended to be used to pass along instructions for how a contract should use or allocate the tokens.\n * @param exclusiveRelayer Address of the relayer who has exclusive rights to fill this deposit. Can be set to\n * 0x0 if no exclusivity period is desired. If so, then must set exclusivityDeadline to 0.\n * @param exclusivityDeadline Timestamp after which any relayer can fill this deposit. Must set\n * to 0 if exclusiveRelayer is set to 0x0, and vice versa.\n * @param fillDeadline Timestamp after which this deposit can no longer be filled.\n */\n function deposit(\n V3SpokePoolInterface spokePool,\n address recipient,\n address inputToken,\n uint256 inputAmount,\n uint256 outputAmount,\n uint256 destinationChainId,\n address exclusiveRelayer,\n uint32 quoteTimestamp,\n uint32 fillDeadline,\n uint32 exclusivityDeadline,\n bytes memory message\n ) external payable {\n require(msg.value == inputAmount, \"msg.value != amount\");\n require(address(spokePool).isContract(), \"spokePool is not a contract\");\n // Set msg.sender as the depositor so that msg.sender can speed up the deposit.\n spokePool.depositV3{ value: msg.value }(\n msg.sender,\n recipient,\n inputToken,\n // @dev Setting outputToken to 0x0 to instruct fillers to use the equivalent token\n // as the originToken on the destination chain.\n address(0),\n inputAmount,\n outputAmount,\n destinationChainId,\n exclusiveRelayer,\n quoteTimestamp,\n fillDeadline,\n exclusivityDeadline,\n message\n );\n }\n}\n" + } + }, + "settings": { + "optimizer": { + "enabled": true, + "runs": 1000000 + }, + "viaIR": true, + "debug": { + "revertStrings": "strip" + }, + "outputSelection": { + "*": { + "*": [ + "abi", + "evm.bytecode", + "evm.deployedBytecode", + "evm.methodIdentifiers", + "metadata", + "devdoc", + "userdoc", + "storageLayout", + "evm.gasEstimates" + ], + "": ["ast"] + } + }, + "metadata": { + "useLiteralContent": true + } + } +} diff --git a/deployments/base/SpokePoolVerifier.json b/deployments/base/SpokePoolVerifier.json index 45dcebf15..821cc0981 100644 --- a/deployments/base/SpokePoolVerifier.json +++ b/deployments/base/SpokePoolVerifier.json @@ -1,10 +1,10 @@ { - "address": "0xB4A8d45647445EA9FC3E1058096142390683dBC2", + "address": "0x4437A1Ee2dFb72954F21A44C3F0F0E2CBA5A5C27", "abi": [ { "inputs": [ { - "internalType": "contract SpokePoolInterface", + "internalType": "contract V3SpokePoolInterface", "name": "spokePool", "type": "address" }, @@ -15,12 +15,17 @@ }, { "internalType": "address", - "name": "originToken", + "name": "inputToken", "type": "address" }, { "internalType": "uint256", - "name": "amount", + "name": "inputAmount", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "outputAmount", "type": "uint256" }, { @@ -29,24 +34,29 @@ "type": "uint256" }, { - "internalType": "int64", - "name": "relayerFeePct", - "type": "int64" + "internalType": "address", + "name": "exclusiveRelayer", + "type": "address" }, { "internalType": "uint32", "name": "quoteTimestamp", "type": "uint32" }, + { + "internalType": "uint32", + "name": "fillDeadline", + "type": "uint32" + }, + { + "internalType": "uint32", + "name": "exclusivityDeadline", + "type": "uint32" + }, { "internalType": "bytes", "name": "message", "type": "bytes" - }, - { - "internalType": "uint256", - "name": "maxCount", - "type": "uint256" } ], "name": "deposit", @@ -55,43 +65,46 @@ "type": "function" } ], - "transactionHash": "0xd939880e88fabd95661c0132c369347db6a01938b27adf3b3552be448cfc8023", + "transactionHash": "0x910c72e994e255a3c07c712f30d34b17bf69eb2058138aa349547dcd65206acd", "receipt": { "to": "0x4e59b44847b379578588920cA78FbF26c0B4956C", "from": "0x9A8f92a830A5cB89a3816e3D267CB7791c16b04D", "contractAddress": null, - "transactionIndex": 13, - "gasUsed": "234906", + "transactionIndex": 41, + "gasUsed": "254525", "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - "blockHash": "0xf60529472adda120bd2e79f2743f85144d667bf38be39c42dcce1c321cbf35a3", - "transactionHash": "0xd939880e88fabd95661c0132c369347db6a01938b27adf3b3552be448cfc8023", + "blockHash": "0x0243bfa4abda6fe0e6b739aa7e4940a0319de3f4d309871c6668dc85f4e48c04", + "transactionHash": "0x910c72e994e255a3c07c712f30d34b17bf69eb2058138aa349547dcd65206acd", "logs": [], - "blockNumber": 12285703, - "cumulativeGasUsed": "2106799", + "blockNumber": 17613151, + "cumulativeGasUsed": "6932033", "status": 1, "byzantium": true }, "args": [], - "numDeployments": 3, - "solcInputHash": "53ab13385da43753d9a657e7780a0560", - "metadata": "{\"compiler\":{\"version\":\"0.8.19+commit.7dd6d404\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"contract SpokePoolInterface\",\"name\":\"spokePool\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"internalType\":\"int64\",\"name\":\"relayerFeePct\",\"type\":\"int64\"},{\"internalType\":\"uint32\",\"name\":\"quoteTimestamp\",\"type\":\"uint32\"},{\"internalType\":\"bytes\",\"name\":\"message\",\"type\":\"bytes\"},{\"internalType\":\"uint256\",\"name\":\"maxCount\",\"type\":\"uint256\"}],\"name\":\"deposit\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"This contract must be deployed via Create2 to the same address on all chains. That way, an errant transaction sent to the wrong chain will be blocked by this contract rather than hitting a dead address. This means that this contract will not work to protect chains, like zkSync, where Create2 address derivations don't match other chains. Source: https://era.zksync.io/docs/reference/architecture/differences-with-ethereum.html#create-create2\",\"kind\":\"dev\",\"methods\":{\"deposit(address,address,address,uint256,uint256,int64,uint32,bytes,uint256)\":{\"details\":\"Protects the caller from losing their ETH (or other native token) by reverting if the SpokePool address they intended to call does not exist on this chain. Because this contract can be deployed at the same address everywhere callers should be protected even if the transaction is submitted to an unintended network. This contract should only be used for native token deposits, as this problem only exists for native tokens.\",\"params\":{\"amount\":\"Amount of tokens to deposit. Will be amount of tokens to receive less fees.\",\"destinationChainId\":\"Denotes network where user will receive funds from SpokePool by a relayer.\",\"maxCount\":\"used to protect the depositor from frontrunning to guarantee their quote remains valid. Note: this is intended to be used to pass along instructions for how a contract should use or allocate the tokens.\",\"message\":\"Arbitrary data that can be used to pass additional information to the recipient along with the tokens. Note: this is intended to be used to pass along instructions for how a contract should use or allocate the tokens.\",\"originToken\":\"Token to lock into this contract to initiate deposit.\",\"quoteTimestamp\":\"Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid to LP pool on HubPool.\",\"recipient\":\"Address to receive funds at on destination chain.\",\"relayerFeePct\":\"% of deposit amount taken out to incentivize a fast relayer.\",\"spokePool\":\"Address of the SpokePool contract that the user is intending to call.\"}}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"deposit(address,address,address,uint256,uint256,int64,uint32,bytes,uint256)\":{\"notice\":\"Passthrough function to `depositV3()` on the SpokePool contract.\"}},\"notice\":\"SpokePoolVerifier is a contract that verifies that the SpokePool exists on this chain before sending ETH to it.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/SpokePoolVerifier.sol\":\"SpokePoolVerifier\"},\"debug\":{\"revertStrings\":\"strip\"},\"evmVersion\":\"paris\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":1000000},\"remappings\":[],\"viaIR\":true},\"sources\":{\"@openzeppelin/contracts/utils/Address.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.9.0) (utils/Address.sol)\\n\\npragma solidity ^0.8.1;\\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 * Furthermore, `isContract` will also return true if the target contract within\\n * the same transaction is already scheduled for destruction by `SELFDESTRUCT`,\\n * which only has an effect at the end of a transaction.\\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 > 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://consensys.net/diligence/blog/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.8.0/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\\n */\\n function sendValue(address payable recipient, uint256 amount) internal {\\n require(address(this).balance >= amount, \\\"Address: insufficient balance\\\");\\n\\n (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 functionCallWithValue(target, data, 0, \\\"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(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, value, \\\"Address: low-level call with value failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\\n * with `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(address(this).balance >= value, \\\"Address: insufficient balance for call\\\");\\n (bool success, bytes memory returndata) = target.call{value: value}(data);\\n return verifyCallResultFromTarget(target, 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 (bool success, bytes memory returndata) = target.staticcall(data);\\n return verifyCallResultFromTarget(target, 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 (bool success, bytes memory returndata) = target.delegatecall(data);\\n return verifyCallResultFromTarget(target, success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling\\n * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.\\n *\\n * _Available since v4.8._\\n */\\n function verifyCallResultFromTarget(\\n address target,\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n if (success) {\\n if (returndata.length == 0) {\\n // only check isContract if the call was successful and the return data is empty\\n // otherwise we already know that it was a contract\\n require(isContract(target), \\\"Address: call to non-contract\\\");\\n }\\n return returndata;\\n } else {\\n _revert(returndata, errorMessage);\\n }\\n }\\n\\n /**\\n * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the\\n * revert reason or 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 _revert(returndata, errorMessage);\\n }\\n }\\n\\n function _revert(bytes memory returndata, string memory errorMessage) private pure {\\n // Look for revert reason and bubble it up if present\\n if (returndata.length > 0) {\\n // The easiest way to bubble the revert reason is using memory via assembly\\n /// @solidity memory-safe-assembly\\n assembly {\\n let returndata_size := mload(returndata)\\n revert(add(32, returndata), returndata_size)\\n }\\n } else {\\n revert(errorMessage);\\n }\\n }\\n}\\n\",\"keccak256\":\"0x006dd67219697fe68d7fbfdea512e7c4cb64a43565ed86171d67e844982da6fa\",\"license\":\"MIT\"},\"contracts/SpokePoolVerifier.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\nimport \\\"@openzeppelin/contracts/utils/Address.sol\\\";\\nimport \\\"./interfaces/SpokePoolInterface.sol\\\";\\n\\n/**\\n * @notice SpokePoolVerifier is a contract that verifies that the SpokePool exists on this chain before sending ETH to it.\\n * @dev This contract must be deployed via Create2 to the same address on all chains. That way, an errant transaction sent\\n * to the wrong chain will be blocked by this contract rather than hitting a dead address. This means that this contract\\n * will not work to protect chains, like zkSync, where Create2 address derivations don't match other chains.\\n * Source: https://era.zksync.io/docs/reference/architecture/differences-with-ethereum.html#create-create2\\n */\\ncontract SpokePoolVerifier {\\n using Address for address;\\n\\n /**\\n * @notice Passthrough function to `depositV3()` on the SpokePool contract.\\n * @dev Protects the caller from losing their ETH (or other native token) by reverting if the SpokePool address\\n * they intended to call does not exist on this chain. Because this contract can be deployed at the same address\\n * everywhere callers should be protected even if the transaction is submitted to an unintended network.\\n * This contract should only be used for native token deposits, as this problem only exists for native tokens.\\n * @param spokePool Address of the SpokePool contract that the user is intending to call.\\n * @param recipient Address to receive funds at on destination chain.\\n * @param originToken Token to lock into this contract to initiate deposit.\\n * @param amount Amount of tokens to deposit. Will be amount of tokens to receive less fees.\\n * @param destinationChainId Denotes network where user will receive funds from SpokePool by a relayer.\\n * @param relayerFeePct % of deposit amount taken out to incentivize a fast relayer.\\n * @param quoteTimestamp Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid\\n * to LP pool on HubPool.\\n * @param message Arbitrary data that can be used to pass additional information to the recipient along with the tokens.\\n * Note: this is intended to be used to pass along instructions for how a contract should use or allocate the tokens.\\n * @param maxCount used to protect the depositor from frontrunning to guarantee their quote remains valid.\\n * Note: this is intended to be used to pass along instructions for how a contract should use or allocate the tokens.\\n */\\n function deposit(\\n SpokePoolInterface spokePool,\\n address recipient,\\n address originToken,\\n uint256 amount,\\n uint256 destinationChainId,\\n int64 relayerFeePct,\\n uint32 quoteTimestamp,\\n bytes memory message,\\n uint256 maxCount\\n ) external payable {\\n require(msg.value == amount, \\\"msg.value != amount\\\");\\n require(address(spokePool).isContract(), \\\"spokePool is not a contract\\\");\\n // Set msg.sender as the depositor so that msg.sender can speed up the deposit.\\n spokePool.depositFor{ value: msg.value }(\\n msg.sender,\\n recipient,\\n originToken,\\n amount,\\n destinationChainId,\\n relayerFeePct,\\n quoteTimestamp,\\n message,\\n maxCount\\n );\\n }\\n}\\n\",\"keccak256\":\"0xfc008c31a2fde7eb0daedaa823b76931225f41ac882b6d1c515d8a38ccda60ec\",\"license\":\"BUSL-1.1\"},\"contracts/interfaces/SpokePoolInterface.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\n/**\\n * @notice Contains common data structures and functions used by all SpokePool implementations.\\n */\\ninterface SpokePoolInterface {\\n // This leaf is meant to be decoded in the SpokePool to pay out successful relayers.\\n struct RelayerRefundLeaf {\\n // This is the amount to return to the HubPool. This occurs when there is a PoolRebalanceLeaf netSendAmount that\\n // is negative. This is just the negative of this value.\\n uint256 amountToReturn;\\n // Used to verify that this is being executed on the correct destination chainId.\\n uint256 chainId;\\n // This array designates how much each of those addresses should be refunded.\\n uint256[] refundAmounts;\\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\\n uint32 leafId;\\n // The associated L2TokenAddress that these claims apply to.\\n address l2TokenAddress;\\n // Must be same length as refundAmounts and designates each address that must be refunded.\\n address[] refundAddresses;\\n }\\n\\n // Stores collection of merkle roots that can be published to this contract from the HubPool, which are referenced\\n // by \\\"data workers\\\" via inclusion proofs to execute leaves in the roots.\\n struct RootBundle {\\n // Merkle root of slow relays that were not fully filled and whose recipient is still owed funds from the LP pool.\\n bytes32 slowRelayRoot;\\n // Merkle root of relayer refunds for successful relays.\\n bytes32 relayerRefundRoot;\\n // This is a 2D bitmap tracking which leaves in the relayer refund root have been claimed, with max size of\\n // 256x(2^248) leaves per root.\\n mapping(uint256 => uint256) claimedBitmap;\\n }\\n\\n function setCrossDomainAdmin(address newCrossDomainAdmin) external;\\n\\n function setHubPool(address newHubPool) external;\\n\\n function setEnableRoute(\\n address originToken,\\n uint256 destinationChainId,\\n bool enable\\n ) external;\\n\\n function pauseDeposits(bool pause) external;\\n\\n function pauseFills(bool pause) external;\\n\\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) external;\\n\\n function emergencyDeleteRootBundle(uint256 rootBundleId) external;\\n\\n function deposit(\\n address recipient,\\n address originToken,\\n uint256 amount,\\n uint256 destinationChainId,\\n int64 relayerFeePct,\\n uint32 quoteTimestamp,\\n bytes memory message,\\n uint256 maxCount\\n ) external payable;\\n\\n function depositFor(\\n address depositor,\\n address recipient,\\n address originToken,\\n uint256 amount,\\n uint256 destinationChainId,\\n int64 relayerFeePct,\\n uint32 quoteTimestamp,\\n bytes memory message,\\n uint256 maxCount\\n ) external payable;\\n\\n function executeRelayerRefundLeaf(\\n uint32 rootBundleId,\\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\\n bytes32[] memory proof\\n ) external payable;\\n\\n function chainId() external view returns (uint256);\\n\\n error NotEOA();\\n error InvalidDepositorSignature();\\n error InvalidRelayerFeePct();\\n error MaxTransferSizeExceeded();\\n error InvalidCrossDomainAdmin();\\n error InvalidHubPool();\\n error DepositsArePaused();\\n error FillsArePaused();\\n}\\n\",\"keccak256\":\"0xc90fbd7e66e2e87e9aacbe93c20cc020cd1fc582c4fd4879807e7dc026943ea0\",\"license\":\"BUSL-1.1\"}},\"version\":1}", - "bytecode": "0x608080604052346100165761034b908161001c8239f35b600080fdfe600436101561000d57600080fd5b6000803560e01c63e0db3fcf1461002357600080fd5b610120807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103115773ffffffffffffffffffffffffffffffffffffffff600435818116810361030d576024359282841684036103095760443583811681036103055760a4358060070b81036103015760c4359063ffffffff8216820361029b5760e43567ffffffffffffffff81116102fd57366023820112156102fd57806004013567ffffffffffffffff81116102d0577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0603f81601f84011601166080016080811067ffffffffffffffff8211176102a357908a929160405280608052366024828401011161029f57602091819060240160a0376080010152606435340361029b578585163b1561029b578585163b1561029b57859694929163ffffffff91878a9896946040519a8b997f541f4f14000000000000000000000000000000000000000000000000000000008b523360048c01521660248a01521660448801526064356064880152608435608488015260070b60a48701521660c485015260e484015260805180610124850152845b8181106102805750908391827fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f6101449389858286010152610104803590850152011681010301923491165af1801561027557610233575080f35b67ffffffffffffffff81116102485760405280f35b6024827f4e487b710000000000000000000000000000000000000000000000000000000081526041600452fd5b6040513d84823e3d90fd5b60a081015187820161014401528795508694506020016101d6565b8780fd5b8280fd5b60248b7f4e487b710000000000000000000000000000000000000000000000000000000081526041600452fd5b60248a7f4e487b710000000000000000000000000000000000000000000000000000000081526041600452fd5b8880fd5b8680fd5b8580fd5b8480fd5b8380fd5b5080fdfea26469706673582212204f81f550f00970671d0755020f959a6599fd76306000e67b424172e1089b949a64736f6c63430008130033", - "deployedBytecode": "0x600436101561000d57600080fd5b6000803560e01c63e0db3fcf1461002357600080fd5b610120807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103115773ffffffffffffffffffffffffffffffffffffffff600435818116810361030d576024359282841684036103095760443583811681036103055760a4358060070b81036103015760c4359063ffffffff8216820361029b5760e43567ffffffffffffffff81116102fd57366023820112156102fd57806004013567ffffffffffffffff81116102d0577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0603f81601f84011601166080016080811067ffffffffffffffff8211176102a357908a929160405280608052366024828401011161029f57602091819060240160a0376080010152606435340361029b578585163b1561029b578585163b1561029b57859694929163ffffffff91878a9896946040519a8b997f541f4f14000000000000000000000000000000000000000000000000000000008b523360048c01521660248a01521660448801526064356064880152608435608488015260070b60a48701521660c485015260e484015260805180610124850152845b8181106102805750908391827fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f6101449389858286010152610104803590850152011681010301923491165af1801561027557610233575080f35b67ffffffffffffffff81116102485760405280f35b6024827f4e487b710000000000000000000000000000000000000000000000000000000081526041600452fd5b6040513d84823e3d90fd5b60a081015187820161014401528795508694506020016101d6565b8780fd5b8280fd5b60248b7f4e487b710000000000000000000000000000000000000000000000000000000081526041600452fd5b60248a7f4e487b710000000000000000000000000000000000000000000000000000000081526041600452fd5b8880fd5b8680fd5b8580fd5b8480fd5b8380fd5b5080fdfea26469706673582212204f81f550f00970671d0755020f959a6599fd76306000e67b424172e1089b949a64736f6c63430008130033", + "numDeployments": 5, + "solcInputHash": "783274f805324492b21545b62eb0dbfe", + "metadata": "{\"compiler\":{\"version\":\"0.8.19+commit.7dd6d404\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"contract V3SpokePoolInterface\",\"name\":\"spokePool\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"inputToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"inputAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"outputAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"exclusiveRelayer\",\"type\":\"address\"},{\"internalType\":\"uint32\",\"name\":\"quoteTimestamp\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"fillDeadline\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"exclusivityDeadline\",\"type\":\"uint32\"},{\"internalType\":\"bytes\",\"name\":\"message\",\"type\":\"bytes\"}],\"name\":\"deposit\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"}],\"devdoc\":{\"custom:security-contact\":\"bugs@across.to\",\"details\":\"This contract must be deployed via Create2 to the same address on all chains. That way, an errant transaction sent to the wrong chain will be blocked by this contract rather than hitting a dead address. This means that this contract will not work to protect chains, like zkSync, where Create2 address derivations don't match other chains. Source: https://era.zksync.io/docs/reference/architecture/differences-with-ethereum.html#create-create2\",\"kind\":\"dev\",\"methods\":{\"deposit(address,address,address,uint256,uint256,uint256,address,uint32,uint32,uint32,bytes)\":{\"details\":\"Protects the caller from losing their ETH (or other native token) by reverting if the SpokePool address they intended to call does not exist on this chain. Because this contract can be deployed at the same address everywhere callers should be protected even if the transaction is submitted to an unintended network. This contract should only be used for native token deposits, as this problem only exists for native tokens.\",\"params\":{\"destinationChainId\":\"Denotes network where user will receive funds from SpokePool by a relayer.\",\"exclusiveRelayer\":\"Address of the relayer who has exclusive rights to fill this deposit. Can be set to 0x0 if no exclusivity period is desired. If so, then must set exclusivityDeadline to 0.\",\"exclusivityDeadline\":\"Timestamp after which any relayer can fill this deposit. Must set to 0 if exclusiveRelayer is set to 0x0, and vice versa.\",\"fillDeadline\":\"Timestamp after which this deposit can no longer be filled.\",\"inputAmount\":\"Amount of tokens to deposit.\",\"inputToken\":\"Token to lock into this contract to initiate deposit.\",\"message\":\"Arbitrary data that can be used to pass additional information to the recipient along with the tokens. Note: this is intended to be used to pass along instructions for how a contract should use or allocate the tokens.\",\"outputAmount\":\"Amount of tokens to receive on destination chain.\",\"quoteTimestamp\":\"Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid to LP pool on HubPool.\",\"recipient\":\"Address to receive funds at on destination chain.\",\"spokePool\":\"Address of the SpokePool contract that the user is intending to call.\"}}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"deposit(address,address,address,uint256,uint256,uint256,address,uint32,uint32,uint32,bytes)\":{\"notice\":\"Passthrough function to `depositV3()` on the SpokePool contract.\"}},\"notice\":\"SpokePoolVerifier is a contract that verifies that the SpokePool exists on this chain before sending ETH to it.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/SpokePoolVerifier.sol\":\"SpokePoolVerifier\"},\"debug\":{\"revertStrings\":\"strip\"},\"evmVersion\":\"paris\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":1000000},\"remappings\":[],\"viaIR\":true},\"sources\":{\"@openzeppelin/contracts/utils/Address.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.9.0) (utils/Address.sol)\\n\\npragma solidity ^0.8.1;\\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 * Furthermore, `isContract` will also return true if the target contract within\\n * the same transaction is already scheduled for destruction by `SELFDESTRUCT`,\\n * which only has an effect at the end of a transaction.\\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 > 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://consensys.net/diligence/blog/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.8.0/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\\n */\\n function sendValue(address payable recipient, uint256 amount) internal {\\n require(address(this).balance >= amount, \\\"Address: insufficient balance\\\");\\n\\n (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 functionCallWithValue(target, data, 0, \\\"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(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, value, \\\"Address: low-level call with value failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\\n * with `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(address(this).balance >= value, \\\"Address: insufficient balance for call\\\");\\n (bool success, bytes memory returndata) = target.call{value: value}(data);\\n return verifyCallResultFromTarget(target, 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 (bool success, bytes memory returndata) = target.staticcall(data);\\n return verifyCallResultFromTarget(target, 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 (bool success, bytes memory returndata) = target.delegatecall(data);\\n return verifyCallResultFromTarget(target, success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling\\n * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.\\n *\\n * _Available since v4.8._\\n */\\n function verifyCallResultFromTarget(\\n address target,\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n if (success) {\\n if (returndata.length == 0) {\\n // only check isContract if the call was successful and the return data is empty\\n // otherwise we already know that it was a contract\\n require(isContract(target), \\\"Address: call to non-contract\\\");\\n }\\n return returndata;\\n } else {\\n _revert(returndata, errorMessage);\\n }\\n }\\n\\n /**\\n * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the\\n * revert reason or 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 _revert(returndata, errorMessage);\\n }\\n }\\n\\n function _revert(bytes memory returndata, string memory errorMessage) private pure {\\n // Look for revert reason and bubble it up if present\\n if (returndata.length > 0) {\\n // The easiest way to bubble the revert reason is using memory via assembly\\n /// @solidity memory-safe-assembly\\n assembly {\\n let returndata_size := mload(returndata)\\n revert(add(32, returndata), returndata_size)\\n }\\n } else {\\n revert(errorMessage);\\n }\\n }\\n}\\n\",\"keccak256\":\"0x006dd67219697fe68d7fbfdea512e7c4cb64a43565ed86171d67e844982da6fa\",\"license\":\"MIT\"},\"contracts/SpokePoolVerifier.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\nimport \\\"@openzeppelin/contracts/utils/Address.sol\\\";\\nimport \\\"./interfaces/V3SpokePoolInterface.sol\\\";\\n\\n/**\\n * @notice SpokePoolVerifier is a contract that verifies that the SpokePool exists on this chain before sending ETH to it.\\n * @dev This contract must be deployed via Create2 to the same address on all chains. That way, an errant transaction sent\\n * to the wrong chain will be blocked by this contract rather than hitting a dead address. This means that this contract\\n * will not work to protect chains, like zkSync, where Create2 address derivations don't match other chains.\\n * Source: https://era.zksync.io/docs/reference/architecture/differences-with-ethereum.html#create-create2\\n * @custom:security-contact bugs@across.to\\n */\\ncontract SpokePoolVerifier {\\n using Address for address;\\n\\n /**\\n * @notice Passthrough function to `depositV3()` on the SpokePool contract.\\n * @dev Protects the caller from losing their ETH (or other native token) by reverting if the SpokePool address\\n * they intended to call does not exist on this chain. Because this contract can be deployed at the same address\\n * everywhere callers should be protected even if the transaction is submitted to an unintended network.\\n * This contract should only be used for native token deposits, as this problem only exists for native tokens.\\n * @param spokePool Address of the SpokePool contract that the user is intending to call.\\n * @param recipient Address to receive funds at on destination chain.\\n * @param inputToken Token to lock into this contract to initiate deposit.\\n * @param inputAmount Amount of tokens to deposit.\\n * @param outputAmount Amount of tokens to receive on destination chain.\\n * @param destinationChainId Denotes network where user will receive funds from SpokePool by a relayer.\\n * @param quoteTimestamp Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid\\n * to LP pool on HubPool.\\n * @param message Arbitrary data that can be used to pass additional information to the recipient along with the tokens.\\n * Note: this is intended to be used to pass along instructions for how a contract should use or allocate the tokens.\\n * @param exclusiveRelayer Address of the relayer who has exclusive rights to fill this deposit. Can be set to\\n * 0x0 if no exclusivity period is desired. If so, then must set exclusivityDeadline to 0.\\n * @param exclusivityDeadline Timestamp after which any relayer can fill this deposit. Must set\\n * to 0 if exclusiveRelayer is set to 0x0, and vice versa.\\n * @param fillDeadline Timestamp after which this deposit can no longer be filled.\\n */\\n function deposit(\\n V3SpokePoolInterface spokePool,\\n address recipient,\\n address inputToken,\\n uint256 inputAmount,\\n uint256 outputAmount,\\n uint256 destinationChainId,\\n address exclusiveRelayer,\\n uint32 quoteTimestamp,\\n uint32 fillDeadline,\\n uint32 exclusivityDeadline,\\n bytes memory message\\n ) external payable {\\n require(msg.value == inputAmount, \\\"msg.value != amount\\\");\\n require(address(spokePool).isContract(), \\\"spokePool is not a contract\\\");\\n // Set msg.sender as the depositor so that msg.sender can speed up the deposit.\\n spokePool.depositV3{ value: msg.value }(\\n msg.sender,\\n recipient,\\n inputToken,\\n // @dev Setting outputToken to 0x0 to instruct fillers to use the equivalent token\\n // as the originToken on the destination chain.\\n address(0),\\n inputAmount,\\n outputAmount,\\n destinationChainId,\\n exclusiveRelayer,\\n quoteTimestamp,\\n fillDeadline,\\n exclusivityDeadline,\\n message\\n );\\n }\\n}\\n\",\"keccak256\":\"0xd5b1ec1b7048634a8b0a7e1e2c68ce51e410157b14778a207b64aff49bc5c6f0\",\"license\":\"BUSL-1.1\"},\"contracts/interfaces/V3SpokePoolInterface.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\n// Contains structs and functions used by SpokePool contracts to facilitate universal settlement.\\ninterface V3SpokePoolInterface {\\n /**************************************\\n * ENUMS *\\n **************************************/\\n\\n // Fill status tracks on-chain state of deposit, uniquely identified by relayHash.\\n enum FillStatus {\\n Unfilled,\\n RequestedSlowFill,\\n Filled\\n }\\n // Fill type is emitted in the FilledRelay event to assist Dataworker with determining which types of\\n // fills to refund (e.g. only fast fills) and whether a fast fill created a sow fill excess.\\n enum FillType {\\n FastFill,\\n // Fast fills are normal fills that do not replace a slow fill request.\\n ReplacedSlowFill,\\n // Replaced slow fills are fast fills that replace a slow fill request. This type is used by the Dataworker\\n // to know when to send excess funds from the SpokePool to the HubPool because they can no longer be used\\n // for a slow fill execution.\\n SlowFill\\n // Slow fills are requested via requestSlowFill and executed by executeSlowRelayLeaf after a bundle containing\\n // the slow fill is validated.\\n }\\n\\n /**************************************\\n * STRUCTS *\\n **************************************/\\n\\n // This struct represents the data to fully specify a **unique** relay submitted on this chain.\\n // This data is hashed with the chainId() and saved by the SpokePool to prevent collisions and protect against\\n // replay attacks on other chains. If any portion of this data differs, the relay is considered to be\\n // completely distinct.\\n struct V3RelayData {\\n // The address that made the deposit on the origin chain.\\n address depositor;\\n // The recipient address on the destination chain.\\n address recipient;\\n // This is the exclusive relayer who can fill the deposit before the exclusivity deadline.\\n address exclusiveRelayer;\\n // Token that is deposited on origin chain by depositor.\\n address inputToken;\\n // Token that is received on destination chain by recipient.\\n address outputToken;\\n // The amount of input token deposited by depositor.\\n uint256 inputAmount;\\n // The amount of output token to be received by recipient.\\n uint256 outputAmount;\\n // Origin chain id.\\n uint256 originChainId;\\n // The id uniquely identifying this deposit on the origin chain.\\n uint32 depositId;\\n // The timestamp on the destination chain after which this deposit can no longer be filled.\\n uint32 fillDeadline;\\n // The timestamp on the destination chain after which any relayer can fill the deposit.\\n uint32 exclusivityDeadline;\\n // Data that is forwarded to the recipient.\\n bytes message;\\n }\\n\\n // Contains parameters passed in by someone who wants to execute a slow relay leaf.\\n struct V3SlowFill {\\n V3RelayData relayData;\\n uint256 chainId;\\n uint256 updatedOutputAmount;\\n }\\n\\n // Contains information about a relay to be sent along with additional information that is not unique to the\\n // relay itself but is required to know how to process the relay. For example, \\\"updatedX\\\" fields can be used\\n // by the relayer to modify fields of the relay with the depositor's permission, and \\\"repaymentChainId\\\" is specified\\n // by the relayer to determine where to take a relayer refund, but doesn't affect the uniqueness of the relay.\\n struct V3RelayExecutionParams {\\n V3RelayData relay;\\n bytes32 relayHash;\\n uint256 updatedOutputAmount;\\n address updatedRecipient;\\n bytes updatedMessage;\\n uint256 repaymentChainId;\\n }\\n\\n // Packs together parameters emitted in FilledV3Relay because there are too many emitted otherwise.\\n // Similar to V3RelayExecutionParams, these parameters are not used to uniquely identify the deposit being\\n // filled so they don't have to be unpacked by all clients.\\n struct V3RelayExecutionEventInfo {\\n address updatedRecipient;\\n bytes updatedMessage;\\n uint256 updatedOutputAmount;\\n FillType fillType;\\n }\\n\\n /**************************************\\n * EVENTS *\\n **************************************/\\n\\n event V3FundsDeposited(\\n address inputToken,\\n address outputToken,\\n uint256 inputAmount,\\n uint256 outputAmount,\\n uint256 indexed destinationChainId,\\n uint32 indexed depositId,\\n uint32 quoteTimestamp,\\n uint32 fillDeadline,\\n uint32 exclusivityDeadline,\\n address indexed depositor,\\n address recipient,\\n address exclusiveRelayer,\\n bytes message\\n );\\n\\n event RequestedSpeedUpV3Deposit(\\n uint256 updatedOutputAmount,\\n uint32 indexed depositId,\\n address indexed depositor,\\n address updatedRecipient,\\n bytes updatedMessage,\\n bytes depositorSignature\\n );\\n\\n event FilledV3Relay(\\n address inputToken,\\n address outputToken,\\n uint256 inputAmount,\\n uint256 outputAmount,\\n uint256 repaymentChainId,\\n uint256 indexed originChainId,\\n uint32 indexed depositId,\\n uint32 fillDeadline,\\n uint32 exclusivityDeadline,\\n address exclusiveRelayer,\\n address indexed relayer,\\n address depositor,\\n address recipient,\\n bytes message,\\n V3RelayExecutionEventInfo relayExecutionInfo\\n );\\n\\n event RequestedV3SlowFill(\\n address inputToken,\\n address outputToken,\\n uint256 inputAmount,\\n uint256 outputAmount,\\n uint256 indexed originChainId,\\n uint32 indexed depositId,\\n uint32 fillDeadline,\\n uint32 exclusivityDeadline,\\n address exclusiveRelayer,\\n address depositor,\\n address recipient,\\n bytes message\\n );\\n\\n /**************************************\\n * FUNCTIONS *\\n **************************************/\\n\\n function depositV3(\\n address depositor,\\n address recipient,\\n address inputToken,\\n address outputToken,\\n uint256 inputAmount,\\n uint256 outputAmount,\\n uint256 destinationChainId,\\n address exclusiveRelayer,\\n uint32 quoteTimestamp,\\n uint32 fillDeadline,\\n uint32 exclusivityDeadline,\\n bytes calldata message\\n ) external payable;\\n\\n function depositV3Now(\\n address depositor,\\n address recipient,\\n address inputToken,\\n address outputToken,\\n uint256 inputAmount,\\n uint256 outputAmount,\\n uint256 destinationChainId,\\n address exclusiveRelayer,\\n uint32 fillDeadlineOffset,\\n uint32 exclusivityDeadline,\\n bytes calldata message\\n ) external payable;\\n\\n function speedUpV3Deposit(\\n address depositor,\\n uint32 depositId,\\n uint256 updatedOutputAmount,\\n address updatedRecipient,\\n bytes calldata updatedMessage,\\n bytes calldata depositorSignature\\n ) external;\\n\\n function fillV3Relay(V3RelayData calldata relayData, uint256 repaymentChainId) external;\\n\\n function fillV3RelayWithUpdatedDeposit(\\n V3RelayData calldata relayData,\\n uint256 repaymentChainId,\\n uint256 updatedOutputAmount,\\n address updatedRecipient,\\n bytes calldata updatedMessage,\\n bytes calldata depositorSignature\\n ) external;\\n\\n function requestV3SlowFill(V3RelayData calldata relayData) external;\\n\\n function executeV3SlowRelayLeaf(\\n V3SlowFill calldata slowFillLeaf,\\n uint32 rootBundleId,\\n bytes32[] calldata proof\\n ) external;\\n\\n /**************************************\\n * ERRORS *\\n **************************************/\\n\\n error DisabledRoute();\\n error InvalidQuoteTimestamp();\\n error InvalidFillDeadline();\\n error InvalidExclusiveRelayer();\\n error InvalidExclusivityDeadline();\\n error MsgValueDoesNotMatchInputAmount();\\n error NotExclusiveRelayer();\\n error NoSlowFillsInExclusivityWindow();\\n error RelayFilled();\\n error InvalidSlowFillRequest();\\n error ExpiredFillDeadline();\\n error InvalidMerkleProof();\\n error InvalidChainId();\\n error InvalidMerkleLeaf();\\n error ClaimedMerkleLeaf();\\n error InvalidPayoutAdjustmentPct();\\n}\\n\",\"keccak256\":\"0x374b7e9cb8afbcaec69cdbcde480676b5d927db84c7f38221331d1226af68d9d\",\"license\":\"BUSL-1.1\"}},\"version\":1}", + "bytecode": "0x60808060405234610016576103a4908161001c8239f35b600080fdfe600436101561000d57600080fd5b6000803560e01c63902e949c1461002357600080fd5b6101607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261036b5773ffffffffffffffffffffffffffffffffffffffff6004358181168103610367576024359082821682036103635760443591838316830361035f5760c435848116810361035b5760e4359063ffffffff928383168303610357576101043590848216820361035357610124359385851685036103225767ffffffffffffffff610144351161032257366023610144350112156103225767ffffffffffffffff6101443560040135116103265767ffffffffffffffff6004610144350135601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f0116608090810191821191101761032657608060046101443590810135601f81017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f011683016040529182905236910160240111610322576101443560048101359060240160a03760a06004610144350135018a90526064353403610322578887163b15610322578887163b1561032257918589979593888296818e9c60409e9b979e519e8f9d8e917f7b9392320000000000000000000000000000000000000000000000000000000083523360048401521690602401521660448c01528b60648c015260643560848c015260843560a48c015260a43560c48c01521660e48a01521661010488015216610124860152166101448401526101648301610180905260805180610184850152845b8181106103075750908391827fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f6101a49389858286010152011681010301923491165af180156102fc576102ba575080f35b67ffffffffffffffff81116102cf5760405280f35b6024827f4e487b710000000000000000000000000000000000000000000000000000000081526041600452fd5b6040513d84823e3d90fd5b60a08101518782016101a40152879550869450602001610266565b8980fd5b60248a7f4e487b710000000000000000000000000000000000000000000000000000000081526041600452fd5b8880fd5b8780fd5b8580fd5b8480fd5b8380fd5b8280fd5b80fdfea26469706673582212201ceff237e6adbd0d3f92e892f7f3f51306c23eac5f7e3f896c2c723d9e5be3a664736f6c63430008130033", + "deployedBytecode": "0x600436101561000d57600080fd5b6000803560e01c63902e949c1461002357600080fd5b6101607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261036b5773ffffffffffffffffffffffffffffffffffffffff6004358181168103610367576024359082821682036103635760443591838316830361035f5760c435848116810361035b5760e4359063ffffffff928383168303610357576101043590848216820361035357610124359385851685036103225767ffffffffffffffff610144351161032257366023610144350112156103225767ffffffffffffffff6101443560040135116103265767ffffffffffffffff6004610144350135601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f0116608090810191821191101761032657608060046101443590810135601f81017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f011683016040529182905236910160240111610322576101443560048101359060240160a03760a06004610144350135018a90526064353403610322578887163b15610322578887163b1561032257918589979593888296818e9c60409e9b979e519e8f9d8e917f7b9392320000000000000000000000000000000000000000000000000000000083523360048401521690602401521660448c01528b60648c015260643560848c015260843560a48c015260a43560c48c01521660e48a01521661010488015216610124860152166101448401526101648301610180905260805180610184850152845b8181106103075750908391827fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f6101a49389858286010152011681010301923491165af180156102fc576102ba575080f35b67ffffffffffffffff81116102cf5760405280f35b6024827f4e487b710000000000000000000000000000000000000000000000000000000081526041600452fd5b6040513d84823e3d90fd5b60a08101518782016101a40152879550869450602001610266565b8980fd5b60248a7f4e487b710000000000000000000000000000000000000000000000000000000081526041600452fd5b8880fd5b8780fd5b8580fd5b8480fd5b8380fd5b8280fd5b80fdfea26469706673582212201ceff237e6adbd0d3f92e892f7f3f51306c23eac5f7e3f896c2c723d9e5be3a664736f6c63430008130033", "devdoc": { + "custom:security-contact": "bugs@across.to", "details": "This contract must be deployed via Create2 to the same address on all chains. That way, an errant transaction sent to the wrong chain will be blocked by this contract rather than hitting a dead address. This means that this contract will not work to protect chains, like zkSync, where Create2 address derivations don't match other chains. Source: https://era.zksync.io/docs/reference/architecture/differences-with-ethereum.html#create-create2", "kind": "dev", "methods": { - "deposit(address,address,address,uint256,uint256,int64,uint32,bytes,uint256)": { + "deposit(address,address,address,uint256,uint256,uint256,address,uint32,uint32,uint32,bytes)": { "details": "Protects the caller from losing their ETH (or other native token) by reverting if the SpokePool address they intended to call does not exist on this chain. Because this contract can be deployed at the same address everywhere callers should be protected even if the transaction is submitted to an unintended network. This contract should only be used for native token deposits, as this problem only exists for native tokens.", "params": { - "amount": "Amount of tokens to deposit. Will be amount of tokens to receive less fees.", "destinationChainId": "Denotes network where user will receive funds from SpokePool by a relayer.", - "maxCount": "used to protect the depositor from frontrunning to guarantee their quote remains valid. Note: this is intended to be used to pass along instructions for how a contract should use or allocate the tokens.", + "exclusiveRelayer": "Address of the relayer who has exclusive rights to fill this deposit. Can be set to 0x0 if no exclusivity period is desired. If so, then must set exclusivityDeadline to 0.", + "exclusivityDeadline": "Timestamp after which any relayer can fill this deposit. Must set to 0 if exclusiveRelayer is set to 0x0, and vice versa.", + "fillDeadline": "Timestamp after which this deposit can no longer be filled.", + "inputAmount": "Amount of tokens to deposit.", + "inputToken": "Token to lock into this contract to initiate deposit.", "message": "Arbitrary data that can be used to pass additional information to the recipient along with the tokens. Note: this is intended to be used to pass along instructions for how a contract should use or allocate the tokens.", - "originToken": "Token to lock into this contract to initiate deposit.", + "outputAmount": "Amount of tokens to receive on destination chain.", "quoteTimestamp": "Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid to LP pool on HubPool.", "recipient": "Address to receive funds at on destination chain.", - "relayerFeePct": "% of deposit amount taken out to incentivize a fast relayer.", "spokePool": "Address of the SpokePool contract that the user is intending to call." } } @@ -101,7 +114,7 @@ "userdoc": { "kind": "user", "methods": { - "deposit(address,address,address,uint256,uint256,int64,uint32,bytes,uint256)": { + "deposit(address,address,address,uint256,uint256,uint256,address,uint32,uint32,uint32,bytes)": { "notice": "Passthrough function to `depositV3()` on the SpokePool contract." } }, diff --git a/deployments/base/solcInputs/1a67233dfe969c05446730f26ab1d2c8.json b/deployments/base/solcInputs/1a67233dfe969c05446730f26ab1d2c8.json new file mode 100644 index 000000000..96daeb1aa --- /dev/null +++ b/deployments/base/solcInputs/1a67233dfe969c05446730f26ab1d2c8.json @@ -0,0 +1,43 @@ +{ + "language": "Solidity", + "sources": { + "@openzeppelin/contracts/utils/Address.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (utils/Address.sol)\n\npragma solidity ^0.8.1;\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 * Furthermore, `isContract` will also return true if the target contract within\n * the same transaction is already scheduled for destruction by `SELFDESTRUCT`,\n * which only has an effect at the end of a transaction.\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 > 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://consensys.net/diligence/blog/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.8.0/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n require(address(this).balance >= amount, \"Address: insufficient balance\");\n\n (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 functionCallWithValue(target, data, 0, \"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(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n return functionCallWithValue(target, data, value, \"Address: low-level call with value failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\n * with `errorMessage` as a fallback revert reason when `target` reverts.\n *\n * _Available since v3.1._\n */\n function functionCallWithValue(\n address target,\n bytes memory data,\n uint256 value,\n string memory errorMessage\n ) internal returns (bytes memory) {\n require(address(this).balance >= value, \"Address: insufficient balance for call\");\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, 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 (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, 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 (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata, errorMessage);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling\n * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.\n *\n * _Available since v4.8._\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata,\n string memory errorMessage\n ) internal view returns (bytes memory) {\n if (success) {\n if (returndata.length == 0) {\n // only check isContract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n require(isContract(target), \"Address: call to non-contract\");\n }\n return returndata;\n } else {\n _revert(returndata, errorMessage);\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the\n * revert reason or 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 _revert(returndata, errorMessage);\n }\n }\n\n function _revert(bytes memory returndata, string memory errorMessage) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length > 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert(errorMessage);\n }\n }\n}\n" + }, + "contracts/interfaces/V3SpokePoolInterface.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n// Contains structs and functions used by SpokePool contracts to facilitate universal settlement.\ninterface V3SpokePoolInterface {\n /**************************************\n * ENUMS *\n **************************************/\n\n // Fill status tracks on-chain state of deposit, uniquely identified by relayHash.\n enum FillStatus {\n Unfilled,\n RequestedSlowFill,\n Filled\n }\n // Fill type is emitted in the FilledRelay event to assist Dataworker with determining which types of\n // fills to refund (e.g. only fast fills) and whether a fast fill created a sow fill excess.\n enum FillType {\n FastFill,\n // Fast fills are normal fills that do not replace a slow fill request.\n ReplacedSlowFill,\n // Replaced slow fills are fast fills that replace a slow fill request. This type is used by the Dataworker\n // to know when to send excess funds from the SpokePool to the HubPool because they can no longer be used\n // for a slow fill execution.\n SlowFill\n // Slow fills are requested via requestSlowFill and executed by executeSlowRelayLeaf after a bundle containing\n // the slow fill is validated.\n }\n\n /**************************************\n * STRUCTS *\n **************************************/\n\n // This struct represents the data to fully specify a **unique** relay submitted on this chain.\n // This data is hashed with the chainId() and saved by the SpokePool to prevent collisions and protect against\n // replay attacks on other chains. If any portion of this data differs, the relay is considered to be\n // completely distinct.\n struct V3RelayData {\n // The address that made the deposit on the origin chain.\n address depositor;\n // The recipient address on the destination chain.\n address recipient;\n // This is the exclusive relayer who can fill the deposit before the exclusivity deadline.\n address exclusiveRelayer;\n // Token that is deposited on origin chain by depositor.\n address inputToken;\n // Token that is received on destination chain by recipient.\n address outputToken;\n // The amount of input token deposited by depositor.\n uint256 inputAmount;\n // The amount of output token to be received by recipient.\n uint256 outputAmount;\n // Origin chain id.\n uint256 originChainId;\n // The id uniquely identifying this deposit on the origin chain.\n uint32 depositId;\n // The timestamp on the destination chain after which this deposit can no longer be filled.\n uint32 fillDeadline;\n // The timestamp on the destination chain after which any relayer can fill the deposit.\n uint32 exclusivityDeadline;\n // Data that is forwarded to the recipient.\n bytes message;\n }\n\n // Contains parameters passed in by someone who wants to execute a slow relay leaf.\n struct V3SlowFill {\n V3RelayData relayData;\n uint256 chainId;\n uint256 updatedOutputAmount;\n }\n\n // Contains information about a relay to be sent along with additional information that is not unique to the\n // relay itself but is required to know how to process the relay. For example, \"updatedX\" fields can be used\n // by the relayer to modify fields of the relay with the depositor's permission, and \"repaymentChainId\" is specified\n // by the relayer to determine where to take a relayer refund, but doesn't affect the uniqueness of the relay.\n struct V3RelayExecutionParams {\n V3RelayData relay;\n bytes32 relayHash;\n uint256 updatedOutputAmount;\n address updatedRecipient;\n bytes updatedMessage;\n uint256 repaymentChainId;\n }\n\n // Packs together parameters emitted in FilledV3Relay because there are too many emitted otherwise.\n // Similar to V3RelayExecutionParams, these parameters are not used to uniquely identify the deposit being\n // filled so they don't have to be unpacked by all clients.\n struct V3RelayExecutionEventInfo {\n address updatedRecipient;\n bytes updatedMessage;\n uint256 updatedOutputAmount;\n FillType fillType;\n }\n\n /**************************************\n * EVENTS *\n **************************************/\n\n event V3FundsDeposited(\n address inputToken,\n address outputToken,\n uint256 inputAmount,\n uint256 outputAmount,\n uint256 indexed destinationChainId,\n uint32 indexed depositId,\n uint32 quoteTimestamp,\n uint32 fillDeadline,\n uint32 exclusivityDeadline,\n address indexed depositor,\n address recipient,\n address exclusiveRelayer,\n bytes message\n );\n\n event RequestedSpeedUpV3Deposit(\n uint256 updatedOutputAmount,\n uint32 indexed depositId,\n address indexed depositor,\n address updatedRecipient,\n bytes updatedMessage,\n bytes depositorSignature\n );\n\n event FilledV3Relay(\n address inputToken,\n address outputToken,\n uint256 inputAmount,\n uint256 outputAmount,\n uint256 repaymentChainId,\n uint256 indexed originChainId,\n uint32 indexed depositId,\n uint32 fillDeadline,\n uint32 exclusivityDeadline,\n address exclusiveRelayer,\n address indexed relayer,\n address depositor,\n address recipient,\n bytes message,\n V3RelayExecutionEventInfo relayExecutionInfo\n );\n\n event RequestedV3SlowFill(\n address inputToken,\n address outputToken,\n uint256 inputAmount,\n uint256 outputAmount,\n uint256 indexed originChainId,\n uint32 indexed depositId,\n uint32 fillDeadline,\n uint32 exclusivityDeadline,\n address exclusiveRelayer,\n address depositor,\n address recipient,\n bytes message\n );\n\n /**************************************\n * FUNCTIONS *\n **************************************/\n\n function depositV3(\n address depositor,\n address recipient,\n address inputToken,\n address outputToken,\n uint256 inputAmount,\n uint256 outputAmount,\n uint256 destinationChainId,\n address exclusiveRelayer,\n uint32 quoteTimestamp,\n uint32 fillDeadline,\n uint32 exclusivityDeadline,\n bytes calldata message\n ) external payable;\n\n function depositV3Now(\n address depositor,\n address recipient,\n address inputToken,\n address outputToken,\n uint256 inputAmount,\n uint256 outputAmount,\n uint256 destinationChainId,\n address exclusiveRelayer,\n uint32 fillDeadlineOffset,\n uint32 exclusivityDeadline,\n bytes calldata message\n ) external payable;\n\n function speedUpV3Deposit(\n address depositor,\n uint32 depositId,\n uint256 updatedOutputAmount,\n address updatedRecipient,\n bytes calldata updatedMessage,\n bytes calldata depositorSignature\n ) external;\n\n function fillV3Relay(V3RelayData calldata relayData, uint256 repaymentChainId) external;\n\n function fillV3RelayWithUpdatedDeposit(\n V3RelayData calldata relayData,\n uint256 repaymentChainId,\n uint256 updatedOutputAmount,\n address updatedRecipient,\n bytes calldata updatedMessage,\n bytes calldata depositorSignature\n ) external;\n\n function requestV3SlowFill(V3RelayData calldata relayData) external;\n\n function executeV3SlowRelayLeaf(\n V3SlowFill calldata slowFillLeaf,\n uint32 rootBundleId,\n bytes32[] calldata proof\n ) external;\n\n /**************************************\n * ERRORS *\n **************************************/\n\n error DisabledRoute();\n error InvalidQuoteTimestamp();\n error InvalidFillDeadline();\n error InvalidExclusiveRelayer();\n error InvalidExclusivityDeadline();\n error MsgValueDoesNotMatchInputAmount();\n error NotExclusiveRelayer();\n error NoSlowFillsInExclusivityWindow();\n error RelayFilled();\n error InvalidSlowFillRequest();\n error ExpiredFillDeadline();\n error InvalidMerkleProof();\n error InvalidChainId();\n error InvalidMerkleLeaf();\n error ClaimedMerkleLeaf();\n error InvalidPayoutAdjustmentPct();\n}\n" + }, + "contracts/SpokePoolVerifier.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/utils/Address.sol\";\nimport \"./interfaces/V3SpokePoolInterface.sol\";\n\n/**\n * @notice SpokePoolVerifier is a contract that verifies that the SpokePool exists on this chain before sending ETH to it.\n * @dev This contract must be deployed via Create2 to the same address on all chains. That way, an errant transaction sent\n * to the wrong chain will be blocked by this contract rather than hitting a dead address. This means that this contract\n * will not work to protect chains, like zkSync, where Create2 address derivations don't match other chains.\n * Source: https://era.zksync.io/docs/reference/architecture/differences-with-ethereum.html#create-create2\n * @custom:security-contact bugs@across.to\n */\ncontract SpokePoolVerifier {\n using Address for address;\n\n /**\n * @notice Passthrough function to `depositV3()` on the SpokePool contract.\n * @dev Protects the caller from losing their ETH (or other native token) by reverting if the SpokePool address\n * they intended to call does not exist on this chain. Because this contract can be deployed at the same address\n * everywhere callers should be protected even if the transaction is submitted to an unintended network.\n * This contract should only be used for native token deposits, as this problem only exists for native tokens.\n * @param spokePool Address of the SpokePool contract that the user is intending to call.\n * @param recipient Address to receive funds at on destination chain.\n * @param inputToken Token to lock into this contract to initiate deposit.\n * @param inputAmount Amount of tokens to deposit.\n * @param outputAmount Amount of tokens to receive on destination chain.\n * @param destinationChainId Denotes network where user will receive funds from SpokePool by a relayer.\n * @param quoteTimestamp Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid\n * to LP pool on HubPool.\n * @param message Arbitrary data that can be used to pass additional information to the recipient along with the tokens.\n * Note: this is intended to be used to pass along instructions for how a contract should use or allocate the tokens.\n * @param exclusiveRelayer Address of the relayer who has exclusive rights to fill this deposit. Can be set to\n * 0x0 if no exclusivity period is desired. If so, then must set exclusivityDeadline to 0.\n * @param exclusivityDeadline Timestamp after which any relayer can fill this deposit. Must set\n * to 0 if exclusiveRelayer is set to 0x0, and vice versa.\n * @param fillDeadline Timestamp after which this deposit can no longer be filled.\n */\n function deposit(\n V3SpokePoolInterface spokePool,\n address recipient,\n address inputToken,\n uint256 inputAmount,\n uint256 outputAmount,\n uint256 destinationChainId,\n uint32 quoteTimestamp,\n bytes memory message,\n address exclusiveRelayer,\n uint32 exclusivityDeadline,\n uint32 fillDeadline\n ) external payable {\n require(msg.value == inputAmount, \"msg.value != amount\");\n require(address(spokePool).isContract(), \"spokePool is not a contract\");\n // Set msg.sender as the depositor so that msg.sender can speed up the deposit.\n spokePool.depositV3{ value: msg.value }(\n msg.sender,\n recipient,\n inputToken,\n // @dev Setting outputToken to 0x0 to instruct fillers to use the equivalent token\n // as the originToken on the destination chain.\n address(0),\n inputAmount,\n outputAmount,\n destinationChainId,\n exclusiveRelayer,\n quoteTimestamp,\n fillDeadline,\n exclusivityDeadline,\n message\n );\n }\n}\n" + } + }, + "settings": { + "optimizer": { + "enabled": true, + "runs": 1000000 + }, + "viaIR": true, + "debug": { + "revertStrings": "strip" + }, + "outputSelection": { + "*": { + "*": [ + "abi", + "evm.bytecode", + "evm.deployedBytecode", + "evm.methodIdentifiers", + "metadata", + "devdoc", + "userdoc", + "storageLayout", + "evm.gasEstimates" + ], + "": ["ast"] + } + }, + "metadata": { + "useLiteralContent": true + } + } +} diff --git a/deployments/base/solcInputs/783274f805324492b21545b62eb0dbfe.json b/deployments/base/solcInputs/783274f805324492b21545b62eb0dbfe.json new file mode 100644 index 000000000..4bcffc07b --- /dev/null +++ b/deployments/base/solcInputs/783274f805324492b21545b62eb0dbfe.json @@ -0,0 +1,43 @@ +{ + "language": "Solidity", + "sources": { + "@openzeppelin/contracts/utils/Address.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (utils/Address.sol)\n\npragma solidity ^0.8.1;\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 * Furthermore, `isContract` will also return true if the target contract within\n * the same transaction is already scheduled for destruction by `SELFDESTRUCT`,\n * which only has an effect at the end of a transaction.\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 > 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://consensys.net/diligence/blog/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.8.0/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n require(address(this).balance >= amount, \"Address: insufficient balance\");\n\n (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 functionCallWithValue(target, data, 0, \"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(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n return functionCallWithValue(target, data, value, \"Address: low-level call with value failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\n * with `errorMessage` as a fallback revert reason when `target` reverts.\n *\n * _Available since v3.1._\n */\n function functionCallWithValue(\n address target,\n bytes memory data,\n uint256 value,\n string memory errorMessage\n ) internal returns (bytes memory) {\n require(address(this).balance >= value, \"Address: insufficient balance for call\");\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, 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 (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, 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 (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata, errorMessage);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling\n * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.\n *\n * _Available since v4.8._\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata,\n string memory errorMessage\n ) internal view returns (bytes memory) {\n if (success) {\n if (returndata.length == 0) {\n // only check isContract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n require(isContract(target), \"Address: call to non-contract\");\n }\n return returndata;\n } else {\n _revert(returndata, errorMessage);\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the\n * revert reason or 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 _revert(returndata, errorMessage);\n }\n }\n\n function _revert(bytes memory returndata, string memory errorMessage) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length > 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert(errorMessage);\n }\n }\n}\n" + }, + "contracts/interfaces/V3SpokePoolInterface.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n// Contains structs and functions used by SpokePool contracts to facilitate universal settlement.\ninterface V3SpokePoolInterface {\n /**************************************\n * ENUMS *\n **************************************/\n\n // Fill status tracks on-chain state of deposit, uniquely identified by relayHash.\n enum FillStatus {\n Unfilled,\n RequestedSlowFill,\n Filled\n }\n // Fill type is emitted in the FilledRelay event to assist Dataworker with determining which types of\n // fills to refund (e.g. only fast fills) and whether a fast fill created a sow fill excess.\n enum FillType {\n FastFill,\n // Fast fills are normal fills that do not replace a slow fill request.\n ReplacedSlowFill,\n // Replaced slow fills are fast fills that replace a slow fill request. This type is used by the Dataworker\n // to know when to send excess funds from the SpokePool to the HubPool because they can no longer be used\n // for a slow fill execution.\n SlowFill\n // Slow fills are requested via requestSlowFill and executed by executeSlowRelayLeaf after a bundle containing\n // the slow fill is validated.\n }\n\n /**************************************\n * STRUCTS *\n **************************************/\n\n // This struct represents the data to fully specify a **unique** relay submitted on this chain.\n // This data is hashed with the chainId() and saved by the SpokePool to prevent collisions and protect against\n // replay attacks on other chains. If any portion of this data differs, the relay is considered to be\n // completely distinct.\n struct V3RelayData {\n // The address that made the deposit on the origin chain.\n address depositor;\n // The recipient address on the destination chain.\n address recipient;\n // This is the exclusive relayer who can fill the deposit before the exclusivity deadline.\n address exclusiveRelayer;\n // Token that is deposited on origin chain by depositor.\n address inputToken;\n // Token that is received on destination chain by recipient.\n address outputToken;\n // The amount of input token deposited by depositor.\n uint256 inputAmount;\n // The amount of output token to be received by recipient.\n uint256 outputAmount;\n // Origin chain id.\n uint256 originChainId;\n // The id uniquely identifying this deposit on the origin chain.\n uint32 depositId;\n // The timestamp on the destination chain after which this deposit can no longer be filled.\n uint32 fillDeadline;\n // The timestamp on the destination chain after which any relayer can fill the deposit.\n uint32 exclusivityDeadline;\n // Data that is forwarded to the recipient.\n bytes message;\n }\n\n // Contains parameters passed in by someone who wants to execute a slow relay leaf.\n struct V3SlowFill {\n V3RelayData relayData;\n uint256 chainId;\n uint256 updatedOutputAmount;\n }\n\n // Contains information about a relay to be sent along with additional information that is not unique to the\n // relay itself but is required to know how to process the relay. For example, \"updatedX\" fields can be used\n // by the relayer to modify fields of the relay with the depositor's permission, and \"repaymentChainId\" is specified\n // by the relayer to determine where to take a relayer refund, but doesn't affect the uniqueness of the relay.\n struct V3RelayExecutionParams {\n V3RelayData relay;\n bytes32 relayHash;\n uint256 updatedOutputAmount;\n address updatedRecipient;\n bytes updatedMessage;\n uint256 repaymentChainId;\n }\n\n // Packs together parameters emitted in FilledV3Relay because there are too many emitted otherwise.\n // Similar to V3RelayExecutionParams, these parameters are not used to uniquely identify the deposit being\n // filled so they don't have to be unpacked by all clients.\n struct V3RelayExecutionEventInfo {\n address updatedRecipient;\n bytes updatedMessage;\n uint256 updatedOutputAmount;\n FillType fillType;\n }\n\n /**************************************\n * EVENTS *\n **************************************/\n\n event V3FundsDeposited(\n address inputToken,\n address outputToken,\n uint256 inputAmount,\n uint256 outputAmount,\n uint256 indexed destinationChainId,\n uint32 indexed depositId,\n uint32 quoteTimestamp,\n uint32 fillDeadline,\n uint32 exclusivityDeadline,\n address indexed depositor,\n address recipient,\n address exclusiveRelayer,\n bytes message\n );\n\n event RequestedSpeedUpV3Deposit(\n uint256 updatedOutputAmount,\n uint32 indexed depositId,\n address indexed depositor,\n address updatedRecipient,\n bytes updatedMessage,\n bytes depositorSignature\n );\n\n event FilledV3Relay(\n address inputToken,\n address outputToken,\n uint256 inputAmount,\n uint256 outputAmount,\n uint256 repaymentChainId,\n uint256 indexed originChainId,\n uint32 indexed depositId,\n uint32 fillDeadline,\n uint32 exclusivityDeadline,\n address exclusiveRelayer,\n address indexed relayer,\n address depositor,\n address recipient,\n bytes message,\n V3RelayExecutionEventInfo relayExecutionInfo\n );\n\n event RequestedV3SlowFill(\n address inputToken,\n address outputToken,\n uint256 inputAmount,\n uint256 outputAmount,\n uint256 indexed originChainId,\n uint32 indexed depositId,\n uint32 fillDeadline,\n uint32 exclusivityDeadline,\n address exclusiveRelayer,\n address depositor,\n address recipient,\n bytes message\n );\n\n /**************************************\n * FUNCTIONS *\n **************************************/\n\n function depositV3(\n address depositor,\n address recipient,\n address inputToken,\n address outputToken,\n uint256 inputAmount,\n uint256 outputAmount,\n uint256 destinationChainId,\n address exclusiveRelayer,\n uint32 quoteTimestamp,\n uint32 fillDeadline,\n uint32 exclusivityDeadline,\n bytes calldata message\n ) external payable;\n\n function depositV3Now(\n address depositor,\n address recipient,\n address inputToken,\n address outputToken,\n uint256 inputAmount,\n uint256 outputAmount,\n uint256 destinationChainId,\n address exclusiveRelayer,\n uint32 fillDeadlineOffset,\n uint32 exclusivityDeadline,\n bytes calldata message\n ) external payable;\n\n function speedUpV3Deposit(\n address depositor,\n uint32 depositId,\n uint256 updatedOutputAmount,\n address updatedRecipient,\n bytes calldata updatedMessage,\n bytes calldata depositorSignature\n ) external;\n\n function fillV3Relay(V3RelayData calldata relayData, uint256 repaymentChainId) external;\n\n function fillV3RelayWithUpdatedDeposit(\n V3RelayData calldata relayData,\n uint256 repaymentChainId,\n uint256 updatedOutputAmount,\n address updatedRecipient,\n bytes calldata updatedMessage,\n bytes calldata depositorSignature\n ) external;\n\n function requestV3SlowFill(V3RelayData calldata relayData) external;\n\n function executeV3SlowRelayLeaf(\n V3SlowFill calldata slowFillLeaf,\n uint32 rootBundleId,\n bytes32[] calldata proof\n ) external;\n\n /**************************************\n * ERRORS *\n **************************************/\n\n error DisabledRoute();\n error InvalidQuoteTimestamp();\n error InvalidFillDeadline();\n error InvalidExclusiveRelayer();\n error InvalidExclusivityDeadline();\n error MsgValueDoesNotMatchInputAmount();\n error NotExclusiveRelayer();\n error NoSlowFillsInExclusivityWindow();\n error RelayFilled();\n error InvalidSlowFillRequest();\n error ExpiredFillDeadline();\n error InvalidMerkleProof();\n error InvalidChainId();\n error InvalidMerkleLeaf();\n error ClaimedMerkleLeaf();\n error InvalidPayoutAdjustmentPct();\n}\n" + }, + "contracts/SpokePoolVerifier.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/utils/Address.sol\";\nimport \"./interfaces/V3SpokePoolInterface.sol\";\n\n/**\n * @notice SpokePoolVerifier is a contract that verifies that the SpokePool exists on this chain before sending ETH to it.\n * @dev This contract must be deployed via Create2 to the same address on all chains. That way, an errant transaction sent\n * to the wrong chain will be blocked by this contract rather than hitting a dead address. This means that this contract\n * will not work to protect chains, like zkSync, where Create2 address derivations don't match other chains.\n * Source: https://era.zksync.io/docs/reference/architecture/differences-with-ethereum.html#create-create2\n * @custom:security-contact bugs@across.to\n */\ncontract SpokePoolVerifier {\n using Address for address;\n\n /**\n * @notice Passthrough function to `depositV3()` on the SpokePool contract.\n * @dev Protects the caller from losing their ETH (or other native token) by reverting if the SpokePool address\n * they intended to call does not exist on this chain. Because this contract can be deployed at the same address\n * everywhere callers should be protected even if the transaction is submitted to an unintended network.\n * This contract should only be used for native token deposits, as this problem only exists for native tokens.\n * @param spokePool Address of the SpokePool contract that the user is intending to call.\n * @param recipient Address to receive funds at on destination chain.\n * @param inputToken Token to lock into this contract to initiate deposit.\n * @param inputAmount Amount of tokens to deposit.\n * @param outputAmount Amount of tokens to receive on destination chain.\n * @param destinationChainId Denotes network where user will receive funds from SpokePool by a relayer.\n * @param quoteTimestamp Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid\n * to LP pool on HubPool.\n * @param message Arbitrary data that can be used to pass additional information to the recipient along with the tokens.\n * Note: this is intended to be used to pass along instructions for how a contract should use or allocate the tokens.\n * @param exclusiveRelayer Address of the relayer who has exclusive rights to fill this deposit. Can be set to\n * 0x0 if no exclusivity period is desired. If so, then must set exclusivityDeadline to 0.\n * @param exclusivityDeadline Timestamp after which any relayer can fill this deposit. Must set\n * to 0 if exclusiveRelayer is set to 0x0, and vice versa.\n * @param fillDeadline Timestamp after which this deposit can no longer be filled.\n */\n function deposit(\n V3SpokePoolInterface spokePool,\n address recipient,\n address inputToken,\n uint256 inputAmount,\n uint256 outputAmount,\n uint256 destinationChainId,\n address exclusiveRelayer,\n uint32 quoteTimestamp,\n uint32 fillDeadline,\n uint32 exclusivityDeadline,\n bytes memory message\n ) external payable {\n require(msg.value == inputAmount, \"msg.value != amount\");\n require(address(spokePool).isContract(), \"spokePool is not a contract\");\n // Set msg.sender as the depositor so that msg.sender can speed up the deposit.\n spokePool.depositV3{ value: msg.value }(\n msg.sender,\n recipient,\n inputToken,\n // @dev Setting outputToken to 0x0 to instruct fillers to use the equivalent token\n // as the originToken on the destination chain.\n address(0),\n inputAmount,\n outputAmount,\n destinationChainId,\n exclusiveRelayer,\n quoteTimestamp,\n fillDeadline,\n exclusivityDeadline,\n message\n );\n }\n}\n" + } + }, + "settings": { + "optimizer": { + "enabled": true, + "runs": 1000000 + }, + "viaIR": true, + "debug": { + "revertStrings": "strip" + }, + "outputSelection": { + "*": { + "*": [ + "abi", + "evm.bytecode", + "evm.deployedBytecode", + "evm.methodIdentifiers", + "metadata", + "devdoc", + "userdoc", + "storageLayout", + "evm.gasEstimates" + ], + "": ["ast"] + } + }, + "metadata": { + "useLiteralContent": true + } + } +} diff --git a/deployments/blast/SpokePoolVerifier.json b/deployments/blast/SpokePoolVerifier.json index 8597bbc87..c20cf46eb 100644 --- a/deployments/blast/SpokePoolVerifier.json +++ b/deployments/blast/SpokePoolVerifier.json @@ -1,10 +1,10 @@ { - "address": "0xB4A8d45647445EA9FC3E1058096142390683dBC2", + "address": "0x4437A1Ee2dFb72954F21A44C3F0F0E2CBA5A5C27", "abi": [ { "inputs": [ { - "internalType": "contract SpokePoolInterface", + "internalType": "contract V3SpokePoolInterface", "name": "spokePool", "type": "address" }, @@ -15,12 +15,17 @@ }, { "internalType": "address", - "name": "originToken", + "name": "inputToken", "type": "address" }, { "internalType": "uint256", - "name": "amount", + "name": "inputAmount", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "outputAmount", "type": "uint256" }, { @@ -29,24 +34,29 @@ "type": "uint256" }, { - "internalType": "int64", - "name": "relayerFeePct", - "type": "int64" + "internalType": "address", + "name": "exclusiveRelayer", + "type": "address" }, { "internalType": "uint32", "name": "quoteTimestamp", "type": "uint32" }, + { + "internalType": "uint32", + "name": "fillDeadline", + "type": "uint32" + }, + { + "internalType": "uint32", + "name": "exclusivityDeadline", + "type": "uint32" + }, { "internalType": "bytes", "name": "message", "type": "bytes" - }, - { - "internalType": "uint256", - "name": "maxCount", - "type": "uint256" } ], "name": "deposit", @@ -55,43 +65,46 @@ "type": "function" } ], - "transactionHash": "0xded1ea25baa317249cd8edce00caaead08a613b69190eba722592d6578bd591e", + "transactionHash": "0xe259337cf4b70f887a1dd10f1968159f400b5b797723ba58355aa77e8dffc0ac", "receipt": { "to": "0x4e59b44847b379578588920cA78FbF26c0B4956C", "from": "0x9A8f92a830A5cB89a3816e3D267CB7791c16b04D", "contractAddress": null, - "transactionIndex": 9, - "gasUsed": "234906", + "transactionIndex": 12, + "gasUsed": "254525", "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - "blockHash": "0xfbc218d3c49f5f4c1e246982da0c7652b6b1647fdbd3f90aa72411bad4b35020", - "transactionHash": "0xded1ea25baa317249cd8edce00caaead08a613b69190eba722592d6578bd591e", + "blockHash": "0x98a9af332947d6cc551e22a90110a5e688926ad66af824f019d2ed67e378e9dd", + "transactionHash": "0xe259337cf4b70f887a1dd10f1968159f400b5b797723ba58355aa77e8dffc0ac", "logs": [], - "blockNumber": 5574513, - "cumulativeGasUsed": "2718365", + "blockNumber": 6603012, + "cumulativeGasUsed": "3474372", "status": 1, "byzantium": true }, "args": [], - "numDeployments": 1, - "solcInputHash": "53ab13385da43753d9a657e7780a0560", - "metadata": "{\"compiler\":{\"version\":\"0.8.19+commit.7dd6d404\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"contract SpokePoolInterface\",\"name\":\"spokePool\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"internalType\":\"int64\",\"name\":\"relayerFeePct\",\"type\":\"int64\"},{\"internalType\":\"uint32\",\"name\":\"quoteTimestamp\",\"type\":\"uint32\"},{\"internalType\":\"bytes\",\"name\":\"message\",\"type\":\"bytes\"},{\"internalType\":\"uint256\",\"name\":\"maxCount\",\"type\":\"uint256\"}],\"name\":\"deposit\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"This contract must be deployed via Create2 to the same address on all chains. That way, an errant transaction sent to the wrong chain will be blocked by this contract rather than hitting a dead address. This means that this contract will not work to protect chains, like zkSync, where Create2 address derivations don't match other chains. Source: https://era.zksync.io/docs/reference/architecture/differences-with-ethereum.html#create-create2\",\"kind\":\"dev\",\"methods\":{\"deposit(address,address,address,uint256,uint256,int64,uint32,bytes,uint256)\":{\"details\":\"Protects the caller from losing their ETH (or other native token) by reverting if the SpokePool address they intended to call does not exist on this chain. Because this contract can be deployed at the same address everywhere callers should be protected even if the transaction is submitted to an unintended network. This contract should only be used for native token deposits, as this problem only exists for native tokens.\",\"params\":{\"amount\":\"Amount of tokens to deposit. Will be amount of tokens to receive less fees.\",\"destinationChainId\":\"Denotes network where user will receive funds from SpokePool by a relayer.\",\"maxCount\":\"used to protect the depositor from frontrunning to guarantee their quote remains valid. Note: this is intended to be used to pass along instructions for how a contract should use or allocate the tokens.\",\"message\":\"Arbitrary data that can be used to pass additional information to the recipient along with the tokens. Note: this is intended to be used to pass along instructions for how a contract should use or allocate the tokens.\",\"originToken\":\"Token to lock into this contract to initiate deposit.\",\"quoteTimestamp\":\"Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid to LP pool on HubPool.\",\"recipient\":\"Address to receive funds at on destination chain.\",\"relayerFeePct\":\"% of deposit amount taken out to incentivize a fast relayer.\",\"spokePool\":\"Address of the SpokePool contract that the user is intending to call.\"}}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"deposit(address,address,address,uint256,uint256,int64,uint32,bytes,uint256)\":{\"notice\":\"Passthrough function to `depositV3()` on the SpokePool contract.\"}},\"notice\":\"SpokePoolVerifier is a contract that verifies that the SpokePool exists on this chain before sending ETH to it.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/SpokePoolVerifier.sol\":\"SpokePoolVerifier\"},\"debug\":{\"revertStrings\":\"strip\"},\"evmVersion\":\"paris\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":1000000},\"remappings\":[],\"viaIR\":true},\"sources\":{\"@openzeppelin/contracts/utils/Address.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.9.0) (utils/Address.sol)\\n\\npragma solidity ^0.8.1;\\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 * Furthermore, `isContract` will also return true if the target contract within\\n * the same transaction is already scheduled for destruction by `SELFDESTRUCT`,\\n * which only has an effect at the end of a transaction.\\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 > 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://consensys.net/diligence/blog/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.8.0/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\\n */\\n function sendValue(address payable recipient, uint256 amount) internal {\\n require(address(this).balance >= amount, \\\"Address: insufficient balance\\\");\\n\\n (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 functionCallWithValue(target, data, 0, \\\"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(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, value, \\\"Address: low-level call with value failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\\n * with `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(address(this).balance >= value, \\\"Address: insufficient balance for call\\\");\\n (bool success, bytes memory returndata) = target.call{value: value}(data);\\n return verifyCallResultFromTarget(target, 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 (bool success, bytes memory returndata) = target.staticcall(data);\\n return verifyCallResultFromTarget(target, 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 (bool success, bytes memory returndata) = target.delegatecall(data);\\n return verifyCallResultFromTarget(target, success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling\\n * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.\\n *\\n * _Available since v4.8._\\n */\\n function verifyCallResultFromTarget(\\n address target,\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n if (success) {\\n if (returndata.length == 0) {\\n // only check isContract if the call was successful and the return data is empty\\n // otherwise we already know that it was a contract\\n require(isContract(target), \\\"Address: call to non-contract\\\");\\n }\\n return returndata;\\n } else {\\n _revert(returndata, errorMessage);\\n }\\n }\\n\\n /**\\n * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the\\n * revert reason or 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 _revert(returndata, errorMessage);\\n }\\n }\\n\\n function _revert(bytes memory returndata, string memory errorMessage) private pure {\\n // Look for revert reason and bubble it up if present\\n if (returndata.length > 0) {\\n // The easiest way to bubble the revert reason is using memory via assembly\\n /// @solidity memory-safe-assembly\\n assembly {\\n let returndata_size := mload(returndata)\\n revert(add(32, returndata), returndata_size)\\n }\\n } else {\\n revert(errorMessage);\\n }\\n }\\n}\\n\",\"keccak256\":\"0x006dd67219697fe68d7fbfdea512e7c4cb64a43565ed86171d67e844982da6fa\",\"license\":\"MIT\"},\"contracts/SpokePoolVerifier.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\nimport \\\"@openzeppelin/contracts/utils/Address.sol\\\";\\nimport \\\"./interfaces/SpokePoolInterface.sol\\\";\\n\\n/**\\n * @notice SpokePoolVerifier is a contract that verifies that the SpokePool exists on this chain before sending ETH to it.\\n * @dev This contract must be deployed via Create2 to the same address on all chains. That way, an errant transaction sent\\n * to the wrong chain will be blocked by this contract rather than hitting a dead address. This means that this contract\\n * will not work to protect chains, like zkSync, where Create2 address derivations don't match other chains.\\n * Source: https://era.zksync.io/docs/reference/architecture/differences-with-ethereum.html#create-create2\\n */\\ncontract SpokePoolVerifier {\\n using Address for address;\\n\\n /**\\n * @notice Passthrough function to `depositV3()` on the SpokePool contract.\\n * @dev Protects the caller from losing their ETH (or other native token) by reverting if the SpokePool address\\n * they intended to call does not exist on this chain. Because this contract can be deployed at the same address\\n * everywhere callers should be protected even if the transaction is submitted to an unintended network.\\n * This contract should only be used for native token deposits, as this problem only exists for native tokens.\\n * @param spokePool Address of the SpokePool contract that the user is intending to call.\\n * @param recipient Address to receive funds at on destination chain.\\n * @param originToken Token to lock into this contract to initiate deposit.\\n * @param amount Amount of tokens to deposit. Will be amount of tokens to receive less fees.\\n * @param destinationChainId Denotes network where user will receive funds from SpokePool by a relayer.\\n * @param relayerFeePct % of deposit amount taken out to incentivize a fast relayer.\\n * @param quoteTimestamp Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid\\n * to LP pool on HubPool.\\n * @param message Arbitrary data that can be used to pass additional information to the recipient along with the tokens.\\n * Note: this is intended to be used to pass along instructions for how a contract should use or allocate the tokens.\\n * @param maxCount used to protect the depositor from frontrunning to guarantee their quote remains valid.\\n * Note: this is intended to be used to pass along instructions for how a contract should use or allocate the tokens.\\n */\\n function deposit(\\n SpokePoolInterface spokePool,\\n address recipient,\\n address originToken,\\n uint256 amount,\\n uint256 destinationChainId,\\n int64 relayerFeePct,\\n uint32 quoteTimestamp,\\n bytes memory message,\\n uint256 maxCount\\n ) external payable {\\n require(msg.value == amount, \\\"msg.value != amount\\\");\\n require(address(spokePool).isContract(), \\\"spokePool is not a contract\\\");\\n // Set msg.sender as the depositor so that msg.sender can speed up the deposit.\\n spokePool.depositFor{ value: msg.value }(\\n msg.sender,\\n recipient,\\n originToken,\\n amount,\\n destinationChainId,\\n relayerFeePct,\\n quoteTimestamp,\\n message,\\n maxCount\\n );\\n }\\n}\\n\",\"keccak256\":\"0xfc008c31a2fde7eb0daedaa823b76931225f41ac882b6d1c515d8a38ccda60ec\",\"license\":\"BUSL-1.1\"},\"contracts/interfaces/SpokePoolInterface.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\n/**\\n * @notice Contains common data structures and functions used by all SpokePool implementations.\\n */\\ninterface SpokePoolInterface {\\n // This leaf is meant to be decoded in the SpokePool to pay out successful relayers.\\n struct RelayerRefundLeaf {\\n // This is the amount to return to the HubPool. This occurs when there is a PoolRebalanceLeaf netSendAmount that\\n // is negative. This is just the negative of this value.\\n uint256 amountToReturn;\\n // Used to verify that this is being executed on the correct destination chainId.\\n uint256 chainId;\\n // This array designates how much each of those addresses should be refunded.\\n uint256[] refundAmounts;\\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\\n uint32 leafId;\\n // The associated L2TokenAddress that these claims apply to.\\n address l2TokenAddress;\\n // Must be same length as refundAmounts and designates each address that must be refunded.\\n address[] refundAddresses;\\n }\\n\\n // Stores collection of merkle roots that can be published to this contract from the HubPool, which are referenced\\n // by \\\"data workers\\\" via inclusion proofs to execute leaves in the roots.\\n struct RootBundle {\\n // Merkle root of slow relays that were not fully filled and whose recipient is still owed funds from the LP pool.\\n bytes32 slowRelayRoot;\\n // Merkle root of relayer refunds for successful relays.\\n bytes32 relayerRefundRoot;\\n // This is a 2D bitmap tracking which leaves in the relayer refund root have been claimed, with max size of\\n // 256x(2^248) leaves per root.\\n mapping(uint256 => uint256) claimedBitmap;\\n }\\n\\n function setCrossDomainAdmin(address newCrossDomainAdmin) external;\\n\\n function setHubPool(address newHubPool) external;\\n\\n function setEnableRoute(\\n address originToken,\\n uint256 destinationChainId,\\n bool enable\\n ) external;\\n\\n function pauseDeposits(bool pause) external;\\n\\n function pauseFills(bool pause) external;\\n\\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) external;\\n\\n function emergencyDeleteRootBundle(uint256 rootBundleId) external;\\n\\n function deposit(\\n address recipient,\\n address originToken,\\n uint256 amount,\\n uint256 destinationChainId,\\n int64 relayerFeePct,\\n uint32 quoteTimestamp,\\n bytes memory message,\\n uint256 maxCount\\n ) external payable;\\n\\n function depositFor(\\n address depositor,\\n address recipient,\\n address originToken,\\n uint256 amount,\\n uint256 destinationChainId,\\n int64 relayerFeePct,\\n uint32 quoteTimestamp,\\n bytes memory message,\\n uint256 maxCount\\n ) external payable;\\n\\n function executeRelayerRefundLeaf(\\n uint32 rootBundleId,\\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\\n bytes32[] memory proof\\n ) external payable;\\n\\n function chainId() external view returns (uint256);\\n\\n error NotEOA();\\n error InvalidDepositorSignature();\\n error InvalidRelayerFeePct();\\n error MaxTransferSizeExceeded();\\n error InvalidCrossDomainAdmin();\\n error InvalidHubPool();\\n error DepositsArePaused();\\n error FillsArePaused();\\n}\\n\",\"keccak256\":\"0xc90fbd7e66e2e87e9aacbe93c20cc020cd1fc582c4fd4879807e7dc026943ea0\",\"license\":\"BUSL-1.1\"}},\"version\":1}", - "bytecode": "0x608080604052346100165761034b908161001c8239f35b600080fdfe600436101561000d57600080fd5b6000803560e01c63e0db3fcf1461002357600080fd5b610120807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103115773ffffffffffffffffffffffffffffffffffffffff600435818116810361030d576024359282841684036103095760443583811681036103055760a4358060070b81036103015760c4359063ffffffff8216820361029b5760e43567ffffffffffffffff81116102fd57366023820112156102fd57806004013567ffffffffffffffff81116102d0577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0603f81601f84011601166080016080811067ffffffffffffffff8211176102a357908a929160405280608052366024828401011161029f57602091819060240160a0376080010152606435340361029b578585163b1561029b578585163b1561029b57859694929163ffffffff91878a9896946040519a8b997f541f4f14000000000000000000000000000000000000000000000000000000008b523360048c01521660248a01521660448801526064356064880152608435608488015260070b60a48701521660c485015260e484015260805180610124850152845b8181106102805750908391827fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f6101449389858286010152610104803590850152011681010301923491165af1801561027557610233575080f35b67ffffffffffffffff81116102485760405280f35b6024827f4e487b710000000000000000000000000000000000000000000000000000000081526041600452fd5b6040513d84823e3d90fd5b60a081015187820161014401528795508694506020016101d6565b8780fd5b8280fd5b60248b7f4e487b710000000000000000000000000000000000000000000000000000000081526041600452fd5b60248a7f4e487b710000000000000000000000000000000000000000000000000000000081526041600452fd5b8880fd5b8680fd5b8580fd5b8480fd5b8380fd5b5080fdfea26469706673582212204f81f550f00970671d0755020f959a6599fd76306000e67b424172e1089b949a64736f6c63430008130033", - "deployedBytecode": "0x600436101561000d57600080fd5b6000803560e01c63e0db3fcf1461002357600080fd5b610120807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103115773ffffffffffffffffffffffffffffffffffffffff600435818116810361030d576024359282841684036103095760443583811681036103055760a4358060070b81036103015760c4359063ffffffff8216820361029b5760e43567ffffffffffffffff81116102fd57366023820112156102fd57806004013567ffffffffffffffff81116102d0577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0603f81601f84011601166080016080811067ffffffffffffffff8211176102a357908a929160405280608052366024828401011161029f57602091819060240160a0376080010152606435340361029b578585163b1561029b578585163b1561029b57859694929163ffffffff91878a9896946040519a8b997f541f4f14000000000000000000000000000000000000000000000000000000008b523360048c01521660248a01521660448801526064356064880152608435608488015260070b60a48701521660c485015260e484015260805180610124850152845b8181106102805750908391827fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f6101449389858286010152610104803590850152011681010301923491165af1801561027557610233575080f35b67ffffffffffffffff81116102485760405280f35b6024827f4e487b710000000000000000000000000000000000000000000000000000000081526041600452fd5b6040513d84823e3d90fd5b60a081015187820161014401528795508694506020016101d6565b8780fd5b8280fd5b60248b7f4e487b710000000000000000000000000000000000000000000000000000000081526041600452fd5b60248a7f4e487b710000000000000000000000000000000000000000000000000000000081526041600452fd5b8880fd5b8680fd5b8580fd5b8480fd5b8380fd5b5080fdfea26469706673582212204f81f550f00970671d0755020f959a6599fd76306000e67b424172e1089b949a64736f6c63430008130033", + "numDeployments": 3, + "solcInputHash": "783274f805324492b21545b62eb0dbfe", + "metadata": "{\"compiler\":{\"version\":\"0.8.19+commit.7dd6d404\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"contract V3SpokePoolInterface\",\"name\":\"spokePool\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"inputToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"inputAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"outputAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"exclusiveRelayer\",\"type\":\"address\"},{\"internalType\":\"uint32\",\"name\":\"quoteTimestamp\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"fillDeadline\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"exclusivityDeadline\",\"type\":\"uint32\"},{\"internalType\":\"bytes\",\"name\":\"message\",\"type\":\"bytes\"}],\"name\":\"deposit\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"}],\"devdoc\":{\"custom:security-contact\":\"bugs@across.to\",\"details\":\"This contract must be deployed via Create2 to the same address on all chains. That way, an errant transaction sent to the wrong chain will be blocked by this contract rather than hitting a dead address. This means that this contract will not work to protect chains, like zkSync, where Create2 address derivations don't match other chains. Source: https://era.zksync.io/docs/reference/architecture/differences-with-ethereum.html#create-create2\",\"kind\":\"dev\",\"methods\":{\"deposit(address,address,address,uint256,uint256,uint256,address,uint32,uint32,uint32,bytes)\":{\"details\":\"Protects the caller from losing their ETH (or other native token) by reverting if the SpokePool address they intended to call does not exist on this chain. Because this contract can be deployed at the same address everywhere callers should be protected even if the transaction is submitted to an unintended network. This contract should only be used for native token deposits, as this problem only exists for native tokens.\",\"params\":{\"destinationChainId\":\"Denotes network where user will receive funds from SpokePool by a relayer.\",\"exclusiveRelayer\":\"Address of the relayer who has exclusive rights to fill this deposit. Can be set to 0x0 if no exclusivity period is desired. If so, then must set exclusivityDeadline to 0.\",\"exclusivityDeadline\":\"Timestamp after which any relayer can fill this deposit. Must set to 0 if exclusiveRelayer is set to 0x0, and vice versa.\",\"fillDeadline\":\"Timestamp after which this deposit can no longer be filled.\",\"inputAmount\":\"Amount of tokens to deposit.\",\"inputToken\":\"Token to lock into this contract to initiate deposit.\",\"message\":\"Arbitrary data that can be used to pass additional information to the recipient along with the tokens. Note: this is intended to be used to pass along instructions for how a contract should use or allocate the tokens.\",\"outputAmount\":\"Amount of tokens to receive on destination chain.\",\"quoteTimestamp\":\"Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid to LP pool on HubPool.\",\"recipient\":\"Address to receive funds at on destination chain.\",\"spokePool\":\"Address of the SpokePool contract that the user is intending to call.\"}}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"deposit(address,address,address,uint256,uint256,uint256,address,uint32,uint32,uint32,bytes)\":{\"notice\":\"Passthrough function to `depositV3()` on the SpokePool contract.\"}},\"notice\":\"SpokePoolVerifier is a contract that verifies that the SpokePool exists on this chain before sending ETH to it.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/SpokePoolVerifier.sol\":\"SpokePoolVerifier\"},\"debug\":{\"revertStrings\":\"strip\"},\"evmVersion\":\"paris\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":1000000},\"remappings\":[],\"viaIR\":true},\"sources\":{\"@openzeppelin/contracts/utils/Address.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.9.0) (utils/Address.sol)\\n\\npragma solidity ^0.8.1;\\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 * Furthermore, `isContract` will also return true if the target contract within\\n * the same transaction is already scheduled for destruction by `SELFDESTRUCT`,\\n * which only has an effect at the end of a transaction.\\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 > 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://consensys.net/diligence/blog/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.8.0/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\\n */\\n function sendValue(address payable recipient, uint256 amount) internal {\\n require(address(this).balance >= amount, \\\"Address: insufficient balance\\\");\\n\\n (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 functionCallWithValue(target, data, 0, \\\"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(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, value, \\\"Address: low-level call with value failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\\n * with `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(address(this).balance >= value, \\\"Address: insufficient balance for call\\\");\\n (bool success, bytes memory returndata) = target.call{value: value}(data);\\n return verifyCallResultFromTarget(target, 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 (bool success, bytes memory returndata) = target.staticcall(data);\\n return verifyCallResultFromTarget(target, 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 (bool success, bytes memory returndata) = target.delegatecall(data);\\n return verifyCallResultFromTarget(target, success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling\\n * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.\\n *\\n * _Available since v4.8._\\n */\\n function verifyCallResultFromTarget(\\n address target,\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n if (success) {\\n if (returndata.length == 0) {\\n // only check isContract if the call was successful and the return data is empty\\n // otherwise we already know that it was a contract\\n require(isContract(target), \\\"Address: call to non-contract\\\");\\n }\\n return returndata;\\n } else {\\n _revert(returndata, errorMessage);\\n }\\n }\\n\\n /**\\n * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the\\n * revert reason or 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 _revert(returndata, errorMessage);\\n }\\n }\\n\\n function _revert(bytes memory returndata, string memory errorMessage) private pure {\\n // Look for revert reason and bubble it up if present\\n if (returndata.length > 0) {\\n // The easiest way to bubble the revert reason is using memory via assembly\\n /// @solidity memory-safe-assembly\\n assembly {\\n let returndata_size := mload(returndata)\\n revert(add(32, returndata), returndata_size)\\n }\\n } else {\\n revert(errorMessage);\\n }\\n }\\n}\\n\",\"keccak256\":\"0x006dd67219697fe68d7fbfdea512e7c4cb64a43565ed86171d67e844982da6fa\",\"license\":\"MIT\"},\"contracts/SpokePoolVerifier.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\nimport \\\"@openzeppelin/contracts/utils/Address.sol\\\";\\nimport \\\"./interfaces/V3SpokePoolInterface.sol\\\";\\n\\n/**\\n * @notice SpokePoolVerifier is a contract that verifies that the SpokePool exists on this chain before sending ETH to it.\\n * @dev This contract must be deployed via Create2 to the same address on all chains. That way, an errant transaction sent\\n * to the wrong chain will be blocked by this contract rather than hitting a dead address. This means that this contract\\n * will not work to protect chains, like zkSync, where Create2 address derivations don't match other chains.\\n * Source: https://era.zksync.io/docs/reference/architecture/differences-with-ethereum.html#create-create2\\n * @custom:security-contact bugs@across.to\\n */\\ncontract SpokePoolVerifier {\\n using Address for address;\\n\\n /**\\n * @notice Passthrough function to `depositV3()` on the SpokePool contract.\\n * @dev Protects the caller from losing their ETH (or other native token) by reverting if the SpokePool address\\n * they intended to call does not exist on this chain. Because this contract can be deployed at the same address\\n * everywhere callers should be protected even if the transaction is submitted to an unintended network.\\n * This contract should only be used for native token deposits, as this problem only exists for native tokens.\\n * @param spokePool Address of the SpokePool contract that the user is intending to call.\\n * @param recipient Address to receive funds at on destination chain.\\n * @param inputToken Token to lock into this contract to initiate deposit.\\n * @param inputAmount Amount of tokens to deposit.\\n * @param outputAmount Amount of tokens to receive on destination chain.\\n * @param destinationChainId Denotes network where user will receive funds from SpokePool by a relayer.\\n * @param quoteTimestamp Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid\\n * to LP pool on HubPool.\\n * @param message Arbitrary data that can be used to pass additional information to the recipient along with the tokens.\\n * Note: this is intended to be used to pass along instructions for how a contract should use or allocate the tokens.\\n * @param exclusiveRelayer Address of the relayer who has exclusive rights to fill this deposit. Can be set to\\n * 0x0 if no exclusivity period is desired. If so, then must set exclusivityDeadline to 0.\\n * @param exclusivityDeadline Timestamp after which any relayer can fill this deposit. Must set\\n * to 0 if exclusiveRelayer is set to 0x0, and vice versa.\\n * @param fillDeadline Timestamp after which this deposit can no longer be filled.\\n */\\n function deposit(\\n V3SpokePoolInterface spokePool,\\n address recipient,\\n address inputToken,\\n uint256 inputAmount,\\n uint256 outputAmount,\\n uint256 destinationChainId,\\n address exclusiveRelayer,\\n uint32 quoteTimestamp,\\n uint32 fillDeadline,\\n uint32 exclusivityDeadline,\\n bytes memory message\\n ) external payable {\\n require(msg.value == inputAmount, \\\"msg.value != amount\\\");\\n require(address(spokePool).isContract(), \\\"spokePool is not a contract\\\");\\n // Set msg.sender as the depositor so that msg.sender can speed up the deposit.\\n spokePool.depositV3{ value: msg.value }(\\n msg.sender,\\n recipient,\\n inputToken,\\n // @dev Setting outputToken to 0x0 to instruct fillers to use the equivalent token\\n // as the originToken on the destination chain.\\n address(0),\\n inputAmount,\\n outputAmount,\\n destinationChainId,\\n exclusiveRelayer,\\n quoteTimestamp,\\n fillDeadline,\\n exclusivityDeadline,\\n message\\n );\\n }\\n}\\n\",\"keccak256\":\"0xd5b1ec1b7048634a8b0a7e1e2c68ce51e410157b14778a207b64aff49bc5c6f0\",\"license\":\"BUSL-1.1\"},\"contracts/interfaces/V3SpokePoolInterface.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\n// Contains structs and functions used by SpokePool contracts to facilitate universal settlement.\\ninterface V3SpokePoolInterface {\\n /**************************************\\n * ENUMS *\\n **************************************/\\n\\n // Fill status tracks on-chain state of deposit, uniquely identified by relayHash.\\n enum FillStatus {\\n Unfilled,\\n RequestedSlowFill,\\n Filled\\n }\\n // Fill type is emitted in the FilledRelay event to assist Dataworker with determining which types of\\n // fills to refund (e.g. only fast fills) and whether a fast fill created a sow fill excess.\\n enum FillType {\\n FastFill,\\n // Fast fills are normal fills that do not replace a slow fill request.\\n ReplacedSlowFill,\\n // Replaced slow fills are fast fills that replace a slow fill request. This type is used by the Dataworker\\n // to know when to send excess funds from the SpokePool to the HubPool because they can no longer be used\\n // for a slow fill execution.\\n SlowFill\\n // Slow fills are requested via requestSlowFill and executed by executeSlowRelayLeaf after a bundle containing\\n // the slow fill is validated.\\n }\\n\\n /**************************************\\n * STRUCTS *\\n **************************************/\\n\\n // This struct represents the data to fully specify a **unique** relay submitted on this chain.\\n // This data is hashed with the chainId() and saved by the SpokePool to prevent collisions and protect against\\n // replay attacks on other chains. If any portion of this data differs, the relay is considered to be\\n // completely distinct.\\n struct V3RelayData {\\n // The address that made the deposit on the origin chain.\\n address depositor;\\n // The recipient address on the destination chain.\\n address recipient;\\n // This is the exclusive relayer who can fill the deposit before the exclusivity deadline.\\n address exclusiveRelayer;\\n // Token that is deposited on origin chain by depositor.\\n address inputToken;\\n // Token that is received on destination chain by recipient.\\n address outputToken;\\n // The amount of input token deposited by depositor.\\n uint256 inputAmount;\\n // The amount of output token to be received by recipient.\\n uint256 outputAmount;\\n // Origin chain id.\\n uint256 originChainId;\\n // The id uniquely identifying this deposit on the origin chain.\\n uint32 depositId;\\n // The timestamp on the destination chain after which this deposit can no longer be filled.\\n uint32 fillDeadline;\\n // The timestamp on the destination chain after which any relayer can fill the deposit.\\n uint32 exclusivityDeadline;\\n // Data that is forwarded to the recipient.\\n bytes message;\\n }\\n\\n // Contains parameters passed in by someone who wants to execute a slow relay leaf.\\n struct V3SlowFill {\\n V3RelayData relayData;\\n uint256 chainId;\\n uint256 updatedOutputAmount;\\n }\\n\\n // Contains information about a relay to be sent along with additional information that is not unique to the\\n // relay itself but is required to know how to process the relay. For example, \\\"updatedX\\\" fields can be used\\n // by the relayer to modify fields of the relay with the depositor's permission, and \\\"repaymentChainId\\\" is specified\\n // by the relayer to determine where to take a relayer refund, but doesn't affect the uniqueness of the relay.\\n struct V3RelayExecutionParams {\\n V3RelayData relay;\\n bytes32 relayHash;\\n uint256 updatedOutputAmount;\\n address updatedRecipient;\\n bytes updatedMessage;\\n uint256 repaymentChainId;\\n }\\n\\n // Packs together parameters emitted in FilledV3Relay because there are too many emitted otherwise.\\n // Similar to V3RelayExecutionParams, these parameters are not used to uniquely identify the deposit being\\n // filled so they don't have to be unpacked by all clients.\\n struct V3RelayExecutionEventInfo {\\n address updatedRecipient;\\n bytes updatedMessage;\\n uint256 updatedOutputAmount;\\n FillType fillType;\\n }\\n\\n /**************************************\\n * EVENTS *\\n **************************************/\\n\\n event V3FundsDeposited(\\n address inputToken,\\n address outputToken,\\n uint256 inputAmount,\\n uint256 outputAmount,\\n uint256 indexed destinationChainId,\\n uint32 indexed depositId,\\n uint32 quoteTimestamp,\\n uint32 fillDeadline,\\n uint32 exclusivityDeadline,\\n address indexed depositor,\\n address recipient,\\n address exclusiveRelayer,\\n bytes message\\n );\\n\\n event RequestedSpeedUpV3Deposit(\\n uint256 updatedOutputAmount,\\n uint32 indexed depositId,\\n address indexed depositor,\\n address updatedRecipient,\\n bytes updatedMessage,\\n bytes depositorSignature\\n );\\n\\n event FilledV3Relay(\\n address inputToken,\\n address outputToken,\\n uint256 inputAmount,\\n uint256 outputAmount,\\n uint256 repaymentChainId,\\n uint256 indexed originChainId,\\n uint32 indexed depositId,\\n uint32 fillDeadline,\\n uint32 exclusivityDeadline,\\n address exclusiveRelayer,\\n address indexed relayer,\\n address depositor,\\n address recipient,\\n bytes message,\\n V3RelayExecutionEventInfo relayExecutionInfo\\n );\\n\\n event RequestedV3SlowFill(\\n address inputToken,\\n address outputToken,\\n uint256 inputAmount,\\n uint256 outputAmount,\\n uint256 indexed originChainId,\\n uint32 indexed depositId,\\n uint32 fillDeadline,\\n uint32 exclusivityDeadline,\\n address exclusiveRelayer,\\n address depositor,\\n address recipient,\\n bytes message\\n );\\n\\n /**************************************\\n * FUNCTIONS *\\n **************************************/\\n\\n function depositV3(\\n address depositor,\\n address recipient,\\n address inputToken,\\n address outputToken,\\n uint256 inputAmount,\\n uint256 outputAmount,\\n uint256 destinationChainId,\\n address exclusiveRelayer,\\n uint32 quoteTimestamp,\\n uint32 fillDeadline,\\n uint32 exclusivityDeadline,\\n bytes calldata message\\n ) external payable;\\n\\n function depositV3Now(\\n address depositor,\\n address recipient,\\n address inputToken,\\n address outputToken,\\n uint256 inputAmount,\\n uint256 outputAmount,\\n uint256 destinationChainId,\\n address exclusiveRelayer,\\n uint32 fillDeadlineOffset,\\n uint32 exclusivityDeadline,\\n bytes calldata message\\n ) external payable;\\n\\n function speedUpV3Deposit(\\n address depositor,\\n uint32 depositId,\\n uint256 updatedOutputAmount,\\n address updatedRecipient,\\n bytes calldata updatedMessage,\\n bytes calldata depositorSignature\\n ) external;\\n\\n function fillV3Relay(V3RelayData calldata relayData, uint256 repaymentChainId) external;\\n\\n function fillV3RelayWithUpdatedDeposit(\\n V3RelayData calldata relayData,\\n uint256 repaymentChainId,\\n uint256 updatedOutputAmount,\\n address updatedRecipient,\\n bytes calldata updatedMessage,\\n bytes calldata depositorSignature\\n ) external;\\n\\n function requestV3SlowFill(V3RelayData calldata relayData) external;\\n\\n function executeV3SlowRelayLeaf(\\n V3SlowFill calldata slowFillLeaf,\\n uint32 rootBundleId,\\n bytes32[] calldata proof\\n ) external;\\n\\n /**************************************\\n * ERRORS *\\n **************************************/\\n\\n error DisabledRoute();\\n error InvalidQuoteTimestamp();\\n error InvalidFillDeadline();\\n error InvalidExclusiveRelayer();\\n error InvalidExclusivityDeadline();\\n error MsgValueDoesNotMatchInputAmount();\\n error NotExclusiveRelayer();\\n error NoSlowFillsInExclusivityWindow();\\n error RelayFilled();\\n error InvalidSlowFillRequest();\\n error ExpiredFillDeadline();\\n error InvalidMerkleProof();\\n error InvalidChainId();\\n error InvalidMerkleLeaf();\\n error ClaimedMerkleLeaf();\\n error InvalidPayoutAdjustmentPct();\\n}\\n\",\"keccak256\":\"0x374b7e9cb8afbcaec69cdbcde480676b5d927db84c7f38221331d1226af68d9d\",\"license\":\"BUSL-1.1\"}},\"version\":1}", + "bytecode": "0x60808060405234610016576103a4908161001c8239f35b600080fdfe600436101561000d57600080fd5b6000803560e01c63902e949c1461002357600080fd5b6101607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261036b5773ffffffffffffffffffffffffffffffffffffffff6004358181168103610367576024359082821682036103635760443591838316830361035f5760c435848116810361035b5760e4359063ffffffff928383168303610357576101043590848216820361035357610124359385851685036103225767ffffffffffffffff610144351161032257366023610144350112156103225767ffffffffffffffff6101443560040135116103265767ffffffffffffffff6004610144350135601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f0116608090810191821191101761032657608060046101443590810135601f81017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f011683016040529182905236910160240111610322576101443560048101359060240160a03760a06004610144350135018a90526064353403610322578887163b15610322578887163b1561032257918589979593888296818e9c60409e9b979e519e8f9d8e917f7b9392320000000000000000000000000000000000000000000000000000000083523360048401521690602401521660448c01528b60648c015260643560848c015260843560a48c015260a43560c48c01521660e48a01521661010488015216610124860152166101448401526101648301610180905260805180610184850152845b8181106103075750908391827fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f6101a49389858286010152011681010301923491165af180156102fc576102ba575080f35b67ffffffffffffffff81116102cf5760405280f35b6024827f4e487b710000000000000000000000000000000000000000000000000000000081526041600452fd5b6040513d84823e3d90fd5b60a08101518782016101a40152879550869450602001610266565b8980fd5b60248a7f4e487b710000000000000000000000000000000000000000000000000000000081526041600452fd5b8880fd5b8780fd5b8580fd5b8480fd5b8380fd5b8280fd5b80fdfea26469706673582212201ceff237e6adbd0d3f92e892f7f3f51306c23eac5f7e3f896c2c723d9e5be3a664736f6c63430008130033", + "deployedBytecode": "0x600436101561000d57600080fd5b6000803560e01c63902e949c1461002357600080fd5b6101607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261036b5773ffffffffffffffffffffffffffffffffffffffff6004358181168103610367576024359082821682036103635760443591838316830361035f5760c435848116810361035b5760e4359063ffffffff928383168303610357576101043590848216820361035357610124359385851685036103225767ffffffffffffffff610144351161032257366023610144350112156103225767ffffffffffffffff6101443560040135116103265767ffffffffffffffff6004610144350135601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f0116608090810191821191101761032657608060046101443590810135601f81017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f011683016040529182905236910160240111610322576101443560048101359060240160a03760a06004610144350135018a90526064353403610322578887163b15610322578887163b1561032257918589979593888296818e9c60409e9b979e519e8f9d8e917f7b9392320000000000000000000000000000000000000000000000000000000083523360048401521690602401521660448c01528b60648c015260643560848c015260843560a48c015260a43560c48c01521660e48a01521661010488015216610124860152166101448401526101648301610180905260805180610184850152845b8181106103075750908391827fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f6101a49389858286010152011681010301923491165af180156102fc576102ba575080f35b67ffffffffffffffff81116102cf5760405280f35b6024827f4e487b710000000000000000000000000000000000000000000000000000000081526041600452fd5b6040513d84823e3d90fd5b60a08101518782016101a40152879550869450602001610266565b8980fd5b60248a7f4e487b710000000000000000000000000000000000000000000000000000000081526041600452fd5b8880fd5b8780fd5b8580fd5b8480fd5b8380fd5b8280fd5b80fdfea26469706673582212201ceff237e6adbd0d3f92e892f7f3f51306c23eac5f7e3f896c2c723d9e5be3a664736f6c63430008130033", "devdoc": { + "custom:security-contact": "bugs@across.to", "details": "This contract must be deployed via Create2 to the same address on all chains. That way, an errant transaction sent to the wrong chain will be blocked by this contract rather than hitting a dead address. This means that this contract will not work to protect chains, like zkSync, where Create2 address derivations don't match other chains. Source: https://era.zksync.io/docs/reference/architecture/differences-with-ethereum.html#create-create2", "kind": "dev", "methods": { - "deposit(address,address,address,uint256,uint256,int64,uint32,bytes,uint256)": { + "deposit(address,address,address,uint256,uint256,uint256,address,uint32,uint32,uint32,bytes)": { "details": "Protects the caller from losing their ETH (or other native token) by reverting if the SpokePool address they intended to call does not exist on this chain. Because this contract can be deployed at the same address everywhere callers should be protected even if the transaction is submitted to an unintended network. This contract should only be used for native token deposits, as this problem only exists for native tokens.", "params": { - "amount": "Amount of tokens to deposit. Will be amount of tokens to receive less fees.", "destinationChainId": "Denotes network where user will receive funds from SpokePool by a relayer.", - "maxCount": "used to protect the depositor from frontrunning to guarantee their quote remains valid. Note: this is intended to be used to pass along instructions for how a contract should use or allocate the tokens.", + "exclusiveRelayer": "Address of the relayer who has exclusive rights to fill this deposit. Can be set to 0x0 if no exclusivity period is desired. If so, then must set exclusivityDeadline to 0.", + "exclusivityDeadline": "Timestamp after which any relayer can fill this deposit. Must set to 0 if exclusiveRelayer is set to 0x0, and vice versa.", + "fillDeadline": "Timestamp after which this deposit can no longer be filled.", + "inputAmount": "Amount of tokens to deposit.", + "inputToken": "Token to lock into this contract to initiate deposit.", "message": "Arbitrary data that can be used to pass additional information to the recipient along with the tokens. Note: this is intended to be used to pass along instructions for how a contract should use or allocate the tokens.", - "originToken": "Token to lock into this contract to initiate deposit.", + "outputAmount": "Amount of tokens to receive on destination chain.", "quoteTimestamp": "Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid to LP pool on HubPool.", "recipient": "Address to receive funds at on destination chain.", - "relayerFeePct": "% of deposit amount taken out to incentivize a fast relayer.", "spokePool": "Address of the SpokePool contract that the user is intending to call." } } @@ -101,7 +114,7 @@ "userdoc": { "kind": "user", "methods": { - "deposit(address,address,address,uint256,uint256,int64,uint32,bytes,uint256)": { + "deposit(address,address,address,uint256,uint256,uint256,address,uint32,uint32,uint32,bytes)": { "notice": "Passthrough function to `depositV3()` on the SpokePool contract." } }, diff --git a/deployments/blast/solcInputs/1a67233dfe969c05446730f26ab1d2c8.json b/deployments/blast/solcInputs/1a67233dfe969c05446730f26ab1d2c8.json new file mode 100644 index 000000000..96daeb1aa --- /dev/null +++ b/deployments/blast/solcInputs/1a67233dfe969c05446730f26ab1d2c8.json @@ -0,0 +1,43 @@ +{ + "language": "Solidity", + "sources": { + "@openzeppelin/contracts/utils/Address.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (utils/Address.sol)\n\npragma solidity ^0.8.1;\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 * Furthermore, `isContract` will also return true if the target contract within\n * the same transaction is already scheduled for destruction by `SELFDESTRUCT`,\n * which only has an effect at the end of a transaction.\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 > 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://consensys.net/diligence/blog/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.8.0/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n require(address(this).balance >= amount, \"Address: insufficient balance\");\n\n (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 functionCallWithValue(target, data, 0, \"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(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n return functionCallWithValue(target, data, value, \"Address: low-level call with value failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\n * with `errorMessage` as a fallback revert reason when `target` reverts.\n *\n * _Available since v3.1._\n */\n function functionCallWithValue(\n address target,\n bytes memory data,\n uint256 value,\n string memory errorMessage\n ) internal returns (bytes memory) {\n require(address(this).balance >= value, \"Address: insufficient balance for call\");\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, 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 (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, 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 (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata, errorMessage);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling\n * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.\n *\n * _Available since v4.8._\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata,\n string memory errorMessage\n ) internal view returns (bytes memory) {\n if (success) {\n if (returndata.length == 0) {\n // only check isContract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n require(isContract(target), \"Address: call to non-contract\");\n }\n return returndata;\n } else {\n _revert(returndata, errorMessage);\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the\n * revert reason or 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 _revert(returndata, errorMessage);\n }\n }\n\n function _revert(bytes memory returndata, string memory errorMessage) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length > 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert(errorMessage);\n }\n }\n}\n" + }, + "contracts/interfaces/V3SpokePoolInterface.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n// Contains structs and functions used by SpokePool contracts to facilitate universal settlement.\ninterface V3SpokePoolInterface {\n /**************************************\n * ENUMS *\n **************************************/\n\n // Fill status tracks on-chain state of deposit, uniquely identified by relayHash.\n enum FillStatus {\n Unfilled,\n RequestedSlowFill,\n Filled\n }\n // Fill type is emitted in the FilledRelay event to assist Dataworker with determining which types of\n // fills to refund (e.g. only fast fills) and whether a fast fill created a sow fill excess.\n enum FillType {\n FastFill,\n // Fast fills are normal fills that do not replace a slow fill request.\n ReplacedSlowFill,\n // Replaced slow fills are fast fills that replace a slow fill request. This type is used by the Dataworker\n // to know when to send excess funds from the SpokePool to the HubPool because they can no longer be used\n // for a slow fill execution.\n SlowFill\n // Slow fills are requested via requestSlowFill and executed by executeSlowRelayLeaf after a bundle containing\n // the slow fill is validated.\n }\n\n /**************************************\n * STRUCTS *\n **************************************/\n\n // This struct represents the data to fully specify a **unique** relay submitted on this chain.\n // This data is hashed with the chainId() and saved by the SpokePool to prevent collisions and protect against\n // replay attacks on other chains. If any portion of this data differs, the relay is considered to be\n // completely distinct.\n struct V3RelayData {\n // The address that made the deposit on the origin chain.\n address depositor;\n // The recipient address on the destination chain.\n address recipient;\n // This is the exclusive relayer who can fill the deposit before the exclusivity deadline.\n address exclusiveRelayer;\n // Token that is deposited on origin chain by depositor.\n address inputToken;\n // Token that is received on destination chain by recipient.\n address outputToken;\n // The amount of input token deposited by depositor.\n uint256 inputAmount;\n // The amount of output token to be received by recipient.\n uint256 outputAmount;\n // Origin chain id.\n uint256 originChainId;\n // The id uniquely identifying this deposit on the origin chain.\n uint32 depositId;\n // The timestamp on the destination chain after which this deposit can no longer be filled.\n uint32 fillDeadline;\n // The timestamp on the destination chain after which any relayer can fill the deposit.\n uint32 exclusivityDeadline;\n // Data that is forwarded to the recipient.\n bytes message;\n }\n\n // Contains parameters passed in by someone who wants to execute a slow relay leaf.\n struct V3SlowFill {\n V3RelayData relayData;\n uint256 chainId;\n uint256 updatedOutputAmount;\n }\n\n // Contains information about a relay to be sent along with additional information that is not unique to the\n // relay itself but is required to know how to process the relay. For example, \"updatedX\" fields can be used\n // by the relayer to modify fields of the relay with the depositor's permission, and \"repaymentChainId\" is specified\n // by the relayer to determine where to take a relayer refund, but doesn't affect the uniqueness of the relay.\n struct V3RelayExecutionParams {\n V3RelayData relay;\n bytes32 relayHash;\n uint256 updatedOutputAmount;\n address updatedRecipient;\n bytes updatedMessage;\n uint256 repaymentChainId;\n }\n\n // Packs together parameters emitted in FilledV3Relay because there are too many emitted otherwise.\n // Similar to V3RelayExecutionParams, these parameters are not used to uniquely identify the deposit being\n // filled so they don't have to be unpacked by all clients.\n struct V3RelayExecutionEventInfo {\n address updatedRecipient;\n bytes updatedMessage;\n uint256 updatedOutputAmount;\n FillType fillType;\n }\n\n /**************************************\n * EVENTS *\n **************************************/\n\n event V3FundsDeposited(\n address inputToken,\n address outputToken,\n uint256 inputAmount,\n uint256 outputAmount,\n uint256 indexed destinationChainId,\n uint32 indexed depositId,\n uint32 quoteTimestamp,\n uint32 fillDeadline,\n uint32 exclusivityDeadline,\n address indexed depositor,\n address recipient,\n address exclusiveRelayer,\n bytes message\n );\n\n event RequestedSpeedUpV3Deposit(\n uint256 updatedOutputAmount,\n uint32 indexed depositId,\n address indexed depositor,\n address updatedRecipient,\n bytes updatedMessage,\n bytes depositorSignature\n );\n\n event FilledV3Relay(\n address inputToken,\n address outputToken,\n uint256 inputAmount,\n uint256 outputAmount,\n uint256 repaymentChainId,\n uint256 indexed originChainId,\n uint32 indexed depositId,\n uint32 fillDeadline,\n uint32 exclusivityDeadline,\n address exclusiveRelayer,\n address indexed relayer,\n address depositor,\n address recipient,\n bytes message,\n V3RelayExecutionEventInfo relayExecutionInfo\n );\n\n event RequestedV3SlowFill(\n address inputToken,\n address outputToken,\n uint256 inputAmount,\n uint256 outputAmount,\n uint256 indexed originChainId,\n uint32 indexed depositId,\n uint32 fillDeadline,\n uint32 exclusivityDeadline,\n address exclusiveRelayer,\n address depositor,\n address recipient,\n bytes message\n );\n\n /**************************************\n * FUNCTIONS *\n **************************************/\n\n function depositV3(\n address depositor,\n address recipient,\n address inputToken,\n address outputToken,\n uint256 inputAmount,\n uint256 outputAmount,\n uint256 destinationChainId,\n address exclusiveRelayer,\n uint32 quoteTimestamp,\n uint32 fillDeadline,\n uint32 exclusivityDeadline,\n bytes calldata message\n ) external payable;\n\n function depositV3Now(\n address depositor,\n address recipient,\n address inputToken,\n address outputToken,\n uint256 inputAmount,\n uint256 outputAmount,\n uint256 destinationChainId,\n address exclusiveRelayer,\n uint32 fillDeadlineOffset,\n uint32 exclusivityDeadline,\n bytes calldata message\n ) external payable;\n\n function speedUpV3Deposit(\n address depositor,\n uint32 depositId,\n uint256 updatedOutputAmount,\n address updatedRecipient,\n bytes calldata updatedMessage,\n bytes calldata depositorSignature\n ) external;\n\n function fillV3Relay(V3RelayData calldata relayData, uint256 repaymentChainId) external;\n\n function fillV3RelayWithUpdatedDeposit(\n V3RelayData calldata relayData,\n uint256 repaymentChainId,\n uint256 updatedOutputAmount,\n address updatedRecipient,\n bytes calldata updatedMessage,\n bytes calldata depositorSignature\n ) external;\n\n function requestV3SlowFill(V3RelayData calldata relayData) external;\n\n function executeV3SlowRelayLeaf(\n V3SlowFill calldata slowFillLeaf,\n uint32 rootBundleId,\n bytes32[] calldata proof\n ) external;\n\n /**************************************\n * ERRORS *\n **************************************/\n\n error DisabledRoute();\n error InvalidQuoteTimestamp();\n error InvalidFillDeadline();\n error InvalidExclusiveRelayer();\n error InvalidExclusivityDeadline();\n error MsgValueDoesNotMatchInputAmount();\n error NotExclusiveRelayer();\n error NoSlowFillsInExclusivityWindow();\n error RelayFilled();\n error InvalidSlowFillRequest();\n error ExpiredFillDeadline();\n error InvalidMerkleProof();\n error InvalidChainId();\n error InvalidMerkleLeaf();\n error ClaimedMerkleLeaf();\n error InvalidPayoutAdjustmentPct();\n}\n" + }, + "contracts/SpokePoolVerifier.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/utils/Address.sol\";\nimport \"./interfaces/V3SpokePoolInterface.sol\";\n\n/**\n * @notice SpokePoolVerifier is a contract that verifies that the SpokePool exists on this chain before sending ETH to it.\n * @dev This contract must be deployed via Create2 to the same address on all chains. That way, an errant transaction sent\n * to the wrong chain will be blocked by this contract rather than hitting a dead address. This means that this contract\n * will not work to protect chains, like zkSync, where Create2 address derivations don't match other chains.\n * Source: https://era.zksync.io/docs/reference/architecture/differences-with-ethereum.html#create-create2\n * @custom:security-contact bugs@across.to\n */\ncontract SpokePoolVerifier {\n using Address for address;\n\n /**\n * @notice Passthrough function to `depositV3()` on the SpokePool contract.\n * @dev Protects the caller from losing their ETH (or other native token) by reverting if the SpokePool address\n * they intended to call does not exist on this chain. Because this contract can be deployed at the same address\n * everywhere callers should be protected even if the transaction is submitted to an unintended network.\n * This contract should only be used for native token deposits, as this problem only exists for native tokens.\n * @param spokePool Address of the SpokePool contract that the user is intending to call.\n * @param recipient Address to receive funds at on destination chain.\n * @param inputToken Token to lock into this contract to initiate deposit.\n * @param inputAmount Amount of tokens to deposit.\n * @param outputAmount Amount of tokens to receive on destination chain.\n * @param destinationChainId Denotes network where user will receive funds from SpokePool by a relayer.\n * @param quoteTimestamp Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid\n * to LP pool on HubPool.\n * @param message Arbitrary data that can be used to pass additional information to the recipient along with the tokens.\n * Note: this is intended to be used to pass along instructions for how a contract should use or allocate the tokens.\n * @param exclusiveRelayer Address of the relayer who has exclusive rights to fill this deposit. Can be set to\n * 0x0 if no exclusivity period is desired. If so, then must set exclusivityDeadline to 0.\n * @param exclusivityDeadline Timestamp after which any relayer can fill this deposit. Must set\n * to 0 if exclusiveRelayer is set to 0x0, and vice versa.\n * @param fillDeadline Timestamp after which this deposit can no longer be filled.\n */\n function deposit(\n V3SpokePoolInterface spokePool,\n address recipient,\n address inputToken,\n uint256 inputAmount,\n uint256 outputAmount,\n uint256 destinationChainId,\n uint32 quoteTimestamp,\n bytes memory message,\n address exclusiveRelayer,\n uint32 exclusivityDeadline,\n uint32 fillDeadline\n ) external payable {\n require(msg.value == inputAmount, \"msg.value != amount\");\n require(address(spokePool).isContract(), \"spokePool is not a contract\");\n // Set msg.sender as the depositor so that msg.sender can speed up the deposit.\n spokePool.depositV3{ value: msg.value }(\n msg.sender,\n recipient,\n inputToken,\n // @dev Setting outputToken to 0x0 to instruct fillers to use the equivalent token\n // as the originToken on the destination chain.\n address(0),\n inputAmount,\n outputAmount,\n destinationChainId,\n exclusiveRelayer,\n quoteTimestamp,\n fillDeadline,\n exclusivityDeadline,\n message\n );\n }\n}\n" + } + }, + "settings": { + "optimizer": { + "enabled": true, + "runs": 1000000 + }, + "viaIR": true, + "debug": { + "revertStrings": "strip" + }, + "outputSelection": { + "*": { + "*": [ + "abi", + "evm.bytecode", + "evm.deployedBytecode", + "evm.methodIdentifiers", + "metadata", + "devdoc", + "userdoc", + "storageLayout", + "evm.gasEstimates" + ], + "": ["ast"] + } + }, + "metadata": { + "useLiteralContent": true + } + } +} diff --git a/deployments/blast/solcInputs/783274f805324492b21545b62eb0dbfe.json b/deployments/blast/solcInputs/783274f805324492b21545b62eb0dbfe.json new file mode 100644 index 000000000..4bcffc07b --- /dev/null +++ b/deployments/blast/solcInputs/783274f805324492b21545b62eb0dbfe.json @@ -0,0 +1,43 @@ +{ + "language": "Solidity", + "sources": { + "@openzeppelin/contracts/utils/Address.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (utils/Address.sol)\n\npragma solidity ^0.8.1;\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 * Furthermore, `isContract` will also return true if the target contract within\n * the same transaction is already scheduled for destruction by `SELFDESTRUCT`,\n * which only has an effect at the end of a transaction.\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 > 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://consensys.net/diligence/blog/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.8.0/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n require(address(this).balance >= amount, \"Address: insufficient balance\");\n\n (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 functionCallWithValue(target, data, 0, \"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(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n return functionCallWithValue(target, data, value, \"Address: low-level call with value failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\n * with `errorMessage` as a fallback revert reason when `target` reverts.\n *\n * _Available since v3.1._\n */\n function functionCallWithValue(\n address target,\n bytes memory data,\n uint256 value,\n string memory errorMessage\n ) internal returns (bytes memory) {\n require(address(this).balance >= value, \"Address: insufficient balance for call\");\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, 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 (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, 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 (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata, errorMessage);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling\n * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.\n *\n * _Available since v4.8._\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata,\n string memory errorMessage\n ) internal view returns (bytes memory) {\n if (success) {\n if (returndata.length == 0) {\n // only check isContract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n require(isContract(target), \"Address: call to non-contract\");\n }\n return returndata;\n } else {\n _revert(returndata, errorMessage);\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the\n * revert reason or 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 _revert(returndata, errorMessage);\n }\n }\n\n function _revert(bytes memory returndata, string memory errorMessage) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length > 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert(errorMessage);\n }\n }\n}\n" + }, + "contracts/interfaces/V3SpokePoolInterface.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n// Contains structs and functions used by SpokePool contracts to facilitate universal settlement.\ninterface V3SpokePoolInterface {\n /**************************************\n * ENUMS *\n **************************************/\n\n // Fill status tracks on-chain state of deposit, uniquely identified by relayHash.\n enum FillStatus {\n Unfilled,\n RequestedSlowFill,\n Filled\n }\n // Fill type is emitted in the FilledRelay event to assist Dataworker with determining which types of\n // fills to refund (e.g. only fast fills) and whether a fast fill created a sow fill excess.\n enum FillType {\n FastFill,\n // Fast fills are normal fills that do not replace a slow fill request.\n ReplacedSlowFill,\n // Replaced slow fills are fast fills that replace a slow fill request. This type is used by the Dataworker\n // to know when to send excess funds from the SpokePool to the HubPool because they can no longer be used\n // for a slow fill execution.\n SlowFill\n // Slow fills are requested via requestSlowFill and executed by executeSlowRelayLeaf after a bundle containing\n // the slow fill is validated.\n }\n\n /**************************************\n * STRUCTS *\n **************************************/\n\n // This struct represents the data to fully specify a **unique** relay submitted on this chain.\n // This data is hashed with the chainId() and saved by the SpokePool to prevent collisions and protect against\n // replay attacks on other chains. If any portion of this data differs, the relay is considered to be\n // completely distinct.\n struct V3RelayData {\n // The address that made the deposit on the origin chain.\n address depositor;\n // The recipient address on the destination chain.\n address recipient;\n // This is the exclusive relayer who can fill the deposit before the exclusivity deadline.\n address exclusiveRelayer;\n // Token that is deposited on origin chain by depositor.\n address inputToken;\n // Token that is received on destination chain by recipient.\n address outputToken;\n // The amount of input token deposited by depositor.\n uint256 inputAmount;\n // The amount of output token to be received by recipient.\n uint256 outputAmount;\n // Origin chain id.\n uint256 originChainId;\n // The id uniquely identifying this deposit on the origin chain.\n uint32 depositId;\n // The timestamp on the destination chain after which this deposit can no longer be filled.\n uint32 fillDeadline;\n // The timestamp on the destination chain after which any relayer can fill the deposit.\n uint32 exclusivityDeadline;\n // Data that is forwarded to the recipient.\n bytes message;\n }\n\n // Contains parameters passed in by someone who wants to execute a slow relay leaf.\n struct V3SlowFill {\n V3RelayData relayData;\n uint256 chainId;\n uint256 updatedOutputAmount;\n }\n\n // Contains information about a relay to be sent along with additional information that is not unique to the\n // relay itself but is required to know how to process the relay. For example, \"updatedX\" fields can be used\n // by the relayer to modify fields of the relay with the depositor's permission, and \"repaymentChainId\" is specified\n // by the relayer to determine where to take a relayer refund, but doesn't affect the uniqueness of the relay.\n struct V3RelayExecutionParams {\n V3RelayData relay;\n bytes32 relayHash;\n uint256 updatedOutputAmount;\n address updatedRecipient;\n bytes updatedMessage;\n uint256 repaymentChainId;\n }\n\n // Packs together parameters emitted in FilledV3Relay because there are too many emitted otherwise.\n // Similar to V3RelayExecutionParams, these parameters are not used to uniquely identify the deposit being\n // filled so they don't have to be unpacked by all clients.\n struct V3RelayExecutionEventInfo {\n address updatedRecipient;\n bytes updatedMessage;\n uint256 updatedOutputAmount;\n FillType fillType;\n }\n\n /**************************************\n * EVENTS *\n **************************************/\n\n event V3FundsDeposited(\n address inputToken,\n address outputToken,\n uint256 inputAmount,\n uint256 outputAmount,\n uint256 indexed destinationChainId,\n uint32 indexed depositId,\n uint32 quoteTimestamp,\n uint32 fillDeadline,\n uint32 exclusivityDeadline,\n address indexed depositor,\n address recipient,\n address exclusiveRelayer,\n bytes message\n );\n\n event RequestedSpeedUpV3Deposit(\n uint256 updatedOutputAmount,\n uint32 indexed depositId,\n address indexed depositor,\n address updatedRecipient,\n bytes updatedMessage,\n bytes depositorSignature\n );\n\n event FilledV3Relay(\n address inputToken,\n address outputToken,\n uint256 inputAmount,\n uint256 outputAmount,\n uint256 repaymentChainId,\n uint256 indexed originChainId,\n uint32 indexed depositId,\n uint32 fillDeadline,\n uint32 exclusivityDeadline,\n address exclusiveRelayer,\n address indexed relayer,\n address depositor,\n address recipient,\n bytes message,\n V3RelayExecutionEventInfo relayExecutionInfo\n );\n\n event RequestedV3SlowFill(\n address inputToken,\n address outputToken,\n uint256 inputAmount,\n uint256 outputAmount,\n uint256 indexed originChainId,\n uint32 indexed depositId,\n uint32 fillDeadline,\n uint32 exclusivityDeadline,\n address exclusiveRelayer,\n address depositor,\n address recipient,\n bytes message\n );\n\n /**************************************\n * FUNCTIONS *\n **************************************/\n\n function depositV3(\n address depositor,\n address recipient,\n address inputToken,\n address outputToken,\n uint256 inputAmount,\n uint256 outputAmount,\n uint256 destinationChainId,\n address exclusiveRelayer,\n uint32 quoteTimestamp,\n uint32 fillDeadline,\n uint32 exclusivityDeadline,\n bytes calldata message\n ) external payable;\n\n function depositV3Now(\n address depositor,\n address recipient,\n address inputToken,\n address outputToken,\n uint256 inputAmount,\n uint256 outputAmount,\n uint256 destinationChainId,\n address exclusiveRelayer,\n uint32 fillDeadlineOffset,\n uint32 exclusivityDeadline,\n bytes calldata message\n ) external payable;\n\n function speedUpV3Deposit(\n address depositor,\n uint32 depositId,\n uint256 updatedOutputAmount,\n address updatedRecipient,\n bytes calldata updatedMessage,\n bytes calldata depositorSignature\n ) external;\n\n function fillV3Relay(V3RelayData calldata relayData, uint256 repaymentChainId) external;\n\n function fillV3RelayWithUpdatedDeposit(\n V3RelayData calldata relayData,\n uint256 repaymentChainId,\n uint256 updatedOutputAmount,\n address updatedRecipient,\n bytes calldata updatedMessage,\n bytes calldata depositorSignature\n ) external;\n\n function requestV3SlowFill(V3RelayData calldata relayData) external;\n\n function executeV3SlowRelayLeaf(\n V3SlowFill calldata slowFillLeaf,\n uint32 rootBundleId,\n bytes32[] calldata proof\n ) external;\n\n /**************************************\n * ERRORS *\n **************************************/\n\n error DisabledRoute();\n error InvalidQuoteTimestamp();\n error InvalidFillDeadline();\n error InvalidExclusiveRelayer();\n error InvalidExclusivityDeadline();\n error MsgValueDoesNotMatchInputAmount();\n error NotExclusiveRelayer();\n error NoSlowFillsInExclusivityWindow();\n error RelayFilled();\n error InvalidSlowFillRequest();\n error ExpiredFillDeadline();\n error InvalidMerkleProof();\n error InvalidChainId();\n error InvalidMerkleLeaf();\n error ClaimedMerkleLeaf();\n error InvalidPayoutAdjustmentPct();\n}\n" + }, + "contracts/SpokePoolVerifier.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/utils/Address.sol\";\nimport \"./interfaces/V3SpokePoolInterface.sol\";\n\n/**\n * @notice SpokePoolVerifier is a contract that verifies that the SpokePool exists on this chain before sending ETH to it.\n * @dev This contract must be deployed via Create2 to the same address on all chains. That way, an errant transaction sent\n * to the wrong chain will be blocked by this contract rather than hitting a dead address. This means that this contract\n * will not work to protect chains, like zkSync, where Create2 address derivations don't match other chains.\n * Source: https://era.zksync.io/docs/reference/architecture/differences-with-ethereum.html#create-create2\n * @custom:security-contact bugs@across.to\n */\ncontract SpokePoolVerifier {\n using Address for address;\n\n /**\n * @notice Passthrough function to `depositV3()` on the SpokePool contract.\n * @dev Protects the caller from losing their ETH (or other native token) by reverting if the SpokePool address\n * they intended to call does not exist on this chain. Because this contract can be deployed at the same address\n * everywhere callers should be protected even if the transaction is submitted to an unintended network.\n * This contract should only be used for native token deposits, as this problem only exists for native tokens.\n * @param spokePool Address of the SpokePool contract that the user is intending to call.\n * @param recipient Address to receive funds at on destination chain.\n * @param inputToken Token to lock into this contract to initiate deposit.\n * @param inputAmount Amount of tokens to deposit.\n * @param outputAmount Amount of tokens to receive on destination chain.\n * @param destinationChainId Denotes network where user will receive funds from SpokePool by a relayer.\n * @param quoteTimestamp Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid\n * to LP pool on HubPool.\n * @param message Arbitrary data that can be used to pass additional information to the recipient along with the tokens.\n * Note: this is intended to be used to pass along instructions for how a contract should use or allocate the tokens.\n * @param exclusiveRelayer Address of the relayer who has exclusive rights to fill this deposit. Can be set to\n * 0x0 if no exclusivity period is desired. If so, then must set exclusivityDeadline to 0.\n * @param exclusivityDeadline Timestamp after which any relayer can fill this deposit. Must set\n * to 0 if exclusiveRelayer is set to 0x0, and vice versa.\n * @param fillDeadline Timestamp after which this deposit can no longer be filled.\n */\n function deposit(\n V3SpokePoolInterface spokePool,\n address recipient,\n address inputToken,\n uint256 inputAmount,\n uint256 outputAmount,\n uint256 destinationChainId,\n address exclusiveRelayer,\n uint32 quoteTimestamp,\n uint32 fillDeadline,\n uint32 exclusivityDeadline,\n bytes memory message\n ) external payable {\n require(msg.value == inputAmount, \"msg.value != amount\");\n require(address(spokePool).isContract(), \"spokePool is not a contract\");\n // Set msg.sender as the depositor so that msg.sender can speed up the deposit.\n spokePool.depositV3{ value: msg.value }(\n msg.sender,\n recipient,\n inputToken,\n // @dev Setting outputToken to 0x0 to instruct fillers to use the equivalent token\n // as the originToken on the destination chain.\n address(0),\n inputAmount,\n outputAmount,\n destinationChainId,\n exclusiveRelayer,\n quoteTimestamp,\n fillDeadline,\n exclusivityDeadline,\n message\n );\n }\n}\n" + } + }, + "settings": { + "optimizer": { + "enabled": true, + "runs": 1000000 + }, + "viaIR": true, + "debug": { + "revertStrings": "strip" + }, + "outputSelection": { + "*": { + "*": [ + "abi", + "evm.bytecode", + "evm.deployedBytecode", + "evm.methodIdentifiers", + "metadata", + "devdoc", + "userdoc", + "storageLayout", + "evm.gasEstimates" + ], + "": ["ast"] + } + }, + "metadata": { + "useLiteralContent": true + } + } +} diff --git a/deployments/deployments.json b/deployments/deployments.json index 5e6fdb6f3..7af3edf50 100644 --- a/deployments/deployments.json +++ b/deployments/deployments.json @@ -17,7 +17,7 @@ "Base_Adapter": { "address": "0xE1421233BF7158A19f89F17c9735F9cbd3D9529c", "blockNumber": 19915087 }, "Linea_Adapter": { "address": "0x7Ea0D1882D610095A45E512B0113f79cA98a8EfE", "blockNumber": 19402413 }, "BondToken": { "address": "0xee1dc6bcf1ee967a350e9ac6caaaa236109002ea", "blockNumber": 17980554 }, - "SpokePoolVerifier": { "address": "0xB4A8d45647445EA9FC3E1058096142390683dBC2", "blockNumber": 19510875 }, + "SpokePoolVerifier": { "address": "0x4437A1Ee2dFb72954F21A44C3F0F0E2CBA5A5C27", "blockNumber": 20392299 }, "Mode_Adapter": { "address": "0xf1B59868697f3925b72889ede818B9E7ba0316d0", "blockNumber": 19914094 }, "MulticallHandler": { "address": "0x924a9f036260DdD5808007E1AA95f08eD08aA569", "blockNumber": 20277013 }, "Lisk_Adapter": { "address": "0x8229E812f20537caA1e8Fb41749b4887B8a75C3B", "blockNumber": 20184545 }, @@ -55,7 +55,7 @@ "1inch_SwapAndBridge": { "address": "0x3E7448657409278C9d6E192b92F2b69B234FCc42", "blockNumber": 120044846 }, "UniswapV3_SwapAndBridge": { "address": "0x6f4A733c7889f038D77D4f540182Dda17423CcbF", "blockNumber": 120044742 }, "AcrossMerkleDistributor": { "address": "0xc8b31410340d57417bE62672f6B53dfB9de30aC2", "blockNumber": 114652330 }, - "SpokePoolVerifier": { "address": "0xB4A8d45647445EA9FC3E1058096142390683dBC2", "blockNumber": 117881120 }, + "SpokePoolVerifier": { "address": "0x4437A1Ee2dFb72954F21A44C3F0F0E2CBA5A5C27", "blockNumber": 123208362 }, "MulticallHandler": { "address": "0x924a9f036260DdD5808007E1AA95f08eD08aA569", "blockNumber": 122513129 } }, "11155420": { @@ -75,7 +75,7 @@ "MintableERC1155": { "address": "0xA15a90E7936A2F8B70E181E955760860D133e56B", "blockNumber": 40600414 }, "PolygonTokenBridger": { "address": "0x0330E9b4D0325cCfF515E81DFbc7754F2a02ac57", "blockNumber": 28604258 }, "SpokePool": { "address": "0x9295ee1d8C5b022Be115A2AD3c30C72E34e7F096", "blockNumber": 41908657 }, - "SpokePoolVerifier": { "address": "0xB4A8d45647445EA9FC3E1058096142390683dBC2", "blockNumber": 55059424 }, + "SpokePoolVerifier": { "address": "0x4437A1Ee2dFb72954F21A44C3F0F0E2CBA5A5C27", "blockNumber": 59840339 }, "1inch_UniversalSwapAndBridge": { "address": "0xf9735e425a36d22636ef4cb75c7a6c63378290ca", "blockNumber": 56529707 @@ -101,7 +101,7 @@ }, "1135": { "SpokePool": { "address": "0x9552a0a6624A23B848060AE5901659CDDa1f83f8", "blockNumber": 2602337 }, - "SpokePoolVerifier": { "address": "0xB4A8d45647445EA9FC3E1058096142390683dBC2", "blockNumber": 2391565 }, + "SpokePoolVerifier": { "address": "0x4437A1Ee2dFb72954F21A44C3F0F0E2CBA5A5C27", "blockNumber": 3643402 }, "MulticallHandler": { "address": "0x924a9f036260DdD5808007E1AA95f08eD08aA569", "blockNumber": 2948231 } }, "4202": { @@ -110,26 +110,26 @@ }, "8453": { "SpokePool": { "address": "0x09aea4b2242abC8bb4BB78D537A67a245A7bEC64", "blockNumber": 2164878 }, - "SpokePoolVerifier": { "address": "0xB4A8d45647445EA9FC3E1058096142390683dBC2", "blockNumber": 12285703 }, + "SpokePoolVerifier": { "address": "0x4437A1Ee2dFb72954F21A44C3F0F0E2CBA5A5C27", "blockNumber": 17613151 }, "1inch_SwapAndBridge": { "address": "0x7CFaBF2eA327009B39f40078011B0Fb714b65926", "blockNumber": 14450808 }, "UniswapV3_SwapAndBridge": { "address": "0xbcfbCE9D92A516e3e7b0762AE218B4194adE34b4", "blockNumber": 14450714 }, "MulticallHandler": { "address": "0x924a9f036260DdD5808007E1AA95f08eD08aA569", "blockNumber": 16917922 } }, "34443": { "SpokePool": { "address": "0x3baD7AD0728f9917d1Bf08af5782dCbD516cDd96", "blockNumber": 8043187 }, - "SpokePoolVerifier": { "address": "0xB4A8d45647445EA9FC3E1058096142390683dBC2", "blockNumber": 8038567 }, + "SpokePoolVerifier": { "address": "0x4437A1Ee2dFb72954F21A44C3F0F0E2CBA5A5C27", "blockNumber": 10924056 }, "MulticallHandler": { "address": "0x924a9f036260DdD5808007E1AA95f08eD08aA569", "blockNumber": 10228826 } }, "42161": { "SpokePool": { "address": "0xe35e9842fceaCA96570B734083f4a58e8F7C5f2A", "blockNumber": 83868041 }, - "SpokePoolVerifier": { "address": "0xB4A8d45647445EA9FC3E1058096142390683dBC2", "blockNumber": 194021369 }, + "SpokePoolVerifier": { "address": "0x4437A1Ee2dFb72954F21A44C3F0F0E2CBA5A5C27", "blockNumber": 236320356 }, "1inch_SwapAndBridge": { "address": "0xC456398D5eE3B93828252e48beDEDbc39e03368E", "blockNumber": 211175795 }, "UniswapV3_SwapAndBridge": { "address": "0xF633b72A4C2Fb73b77A379bf72864A825aD35b6D", "blockNumber": 211175481 }, "MulticallHandler": { "address": "0x924a9f036260DdD5808007E1AA95f08eD08aA569", "blockNumber": 230779625 } }, "59144": { "SpokePool": { "address": "0x7E63A5f1a8F0B4d0934B2f2327DAED3F6bb2ee75", "blockNumber": 2721169 }, - "SpokePoolVerifier": { "address": "0xB4A8d45647445EA9FC3E1058096142390683dBC2", "blockNumber": 3101687 }, + "SpokePoolVerifier": { "address": "0x4437A1Ee2dFb72954F21A44C3F0F0E2CBA5A5C27", "blockNumber": 7306202 }, "MulticallHandler": { "address": "0x1015c58894961F4F7Dd7D68ba033e28Ed3ee1cDB", "blockNumber": 5669220 } }, "84531": { "SpokePool": { "address": "0x1F5AA71C79ec6a11FC55789ed32dAE3B64d75791", "blockNumber": 7992905 } }, @@ -153,7 +153,7 @@ }, "81457": { "SpokePool": { "address": "0x2D509190Ed0172ba588407D4c2df918F955Cc6E1", "blockNumber": 5574280 }, - "SpokePoolVerifier": { "address": "0xB4A8d45647445EA9FC3E1058096142390683dBC2", "blockNumber": 5574513 }, + "SpokePoolVerifier": { "address": "0x4437A1Ee2dFb72954F21A44C3F0F0E2CBA5A5C27", "blockNumber": 6603012 }, "MulticallHandler": { "address": "0x924a9f036260DdD5808007E1AA95f08eD08aA569", "blockNumber": 5876291 } }, "421611": { "SpokePool": { "address": "0x3BED21dAe767e4Df894B31b14aD32369cE4bad8b", "blockNumber": 10523275 } }, @@ -164,7 +164,7 @@ }, "534352": { "SpokePool": { "address": "0x3baD7AD0728f9917d1Bf08af5782dCbD516cDd96", "blockNumber": 7489705 }, - "SpokePoolVerifier": { "address": "0xB4A8d45647445EA9FC3E1058096142390683dBC2", "blockNumber": 7490003 }, + "SpokePoolVerifier": { "address": "0x4437A1Ee2dFb72954F21A44C3F0F0E2CBA5A5C27", "blockNumber": 7800129 }, "MulticallHandler": { "address": "0x924a9f036260DdD5808007E1AA95f08eD08aA569", "blockNumber": 7489978 } }, "11155111": { diff --git a/deployments/linea/SpokePoolVerifier.json b/deployments/linea/SpokePoolVerifier.json index 787c03837..3fc843021 100644 --- a/deployments/linea/SpokePoolVerifier.json +++ b/deployments/linea/SpokePoolVerifier.json @@ -1,10 +1,10 @@ { - "address": "0xB4A8d45647445EA9FC3E1058096142390683dBC2", + "address": "0x4437A1Ee2dFb72954F21A44C3F0F0E2CBA5A5C27", "abi": [ { "inputs": [ { - "internalType": "contract SpokePoolInterface", + "internalType": "contract V3SpokePoolInterface", "name": "spokePool", "type": "address" }, @@ -15,12 +15,17 @@ }, { "internalType": "address", - "name": "originToken", + "name": "inputToken", "type": "address" }, { "internalType": "uint256", - "name": "amount", + "name": "inputAmount", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "outputAmount", "type": "uint256" }, { @@ -29,24 +34,29 @@ "type": "uint256" }, { - "internalType": "int64", - "name": "relayerFeePct", - "type": "int64" + "internalType": "address", + "name": "exclusiveRelayer", + "type": "address" }, { "internalType": "uint32", "name": "quoteTimestamp", "type": "uint32" }, + { + "internalType": "uint32", + "name": "fillDeadline", + "type": "uint32" + }, + { + "internalType": "uint32", + "name": "exclusivityDeadline", + "type": "uint32" + }, { "internalType": "bytes", "name": "message", "type": "bytes" - }, - { - "internalType": "uint256", - "name": "maxCount", - "type": "uint256" } ], "name": "deposit", @@ -55,43 +65,46 @@ "type": "function" } ], - "transactionHash": "0x52cf306d97c4fd4e9bce9249ba4af2b88073ffbd2998cca24d1877b560d06ba4", + "transactionHash": "0xd3c7540f052f228cb68c7b4e7592f2b4e7a799a795c0cee3f6900d478b40576b", "receipt": { "to": "0x4e59b44847b379578588920cA78FbF26c0B4956C", "from": "0x9A8f92a830A5cB89a3816e3D267CB7791c16b04D", "contractAddress": null, - "transactionIndex": 6, - "gasUsed": "234850", + "transactionIndex": 15, + "gasUsed": "254465", "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - "blockHash": "0x55a384c9cf158f574babfa9dbc932ba81cb74c3eafe8a1dd4d58e3c34cd68040", - "transactionHash": "0x52cf306d97c4fd4e9bce9249ba4af2b88073ffbd2998cca24d1877b560d06ba4", + "blockHash": "0x83bcc41e215210056ce45aadbc24321c0939569fc73c04d8908702a3f02c45ee", + "transactionHash": "0xd3c7540f052f228cb68c7b4e7592f2b4e7a799a795c0cee3f6900d478b40576b", "logs": [], - "blockNumber": 3101687, - "cumulativeGasUsed": "692894", + "blockNumber": 7306202, + "cumulativeGasUsed": "1491324", "status": 1, "byzantium": true }, "args": [], - "numDeployments": 1, - "solcInputHash": "53ab13385da43753d9a657e7780a0560", - "metadata": "{\"compiler\":{\"version\":\"0.8.19+commit.7dd6d404\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"contract SpokePoolInterface\",\"name\":\"spokePool\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"internalType\":\"int64\",\"name\":\"relayerFeePct\",\"type\":\"int64\"},{\"internalType\":\"uint32\",\"name\":\"quoteTimestamp\",\"type\":\"uint32\"},{\"internalType\":\"bytes\",\"name\":\"message\",\"type\":\"bytes\"},{\"internalType\":\"uint256\",\"name\":\"maxCount\",\"type\":\"uint256\"}],\"name\":\"deposit\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"This contract must be deployed via Create2 to the same address on all chains. That way, an errant transaction sent to the wrong chain will be blocked by this contract rather than hitting a dead address. This means that this contract will not work to protect chains, like zkSync, where Create2 address derivations don't match other chains. Source: https://era.zksync.io/docs/reference/architecture/differences-with-ethereum.html#create-create2\",\"kind\":\"dev\",\"methods\":{\"deposit(address,address,address,uint256,uint256,int64,uint32,bytes,uint256)\":{\"details\":\"Protects the caller from losing their ETH (or other native token) by reverting if the SpokePool address they intended to call does not exist on this chain. Because this contract can be deployed at the same address everywhere callers should be protected even if the transaction is submitted to an unintended network. This contract should only be used for native token deposits, as this problem only exists for native tokens.\",\"params\":{\"amount\":\"Amount of tokens to deposit. Will be amount of tokens to receive less fees.\",\"destinationChainId\":\"Denotes network where user will receive funds from SpokePool by a relayer.\",\"maxCount\":\"used to protect the depositor from frontrunning to guarantee their quote remains valid. Note: this is intended to be used to pass along instructions for how a contract should use or allocate the tokens.\",\"message\":\"Arbitrary data that can be used to pass additional information to the recipient along with the tokens. Note: this is intended to be used to pass along instructions for how a contract should use or allocate the tokens.\",\"originToken\":\"Token to lock into this contract to initiate deposit.\",\"quoteTimestamp\":\"Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid to LP pool on HubPool.\",\"recipient\":\"Address to receive funds at on destination chain.\",\"relayerFeePct\":\"% of deposit amount taken out to incentivize a fast relayer.\",\"spokePool\":\"Address of the SpokePool contract that the user is intending to call.\"}}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"deposit(address,address,address,uint256,uint256,int64,uint32,bytes,uint256)\":{\"notice\":\"Passthrough function to `depositV3()` on the SpokePool contract.\"}},\"notice\":\"SpokePoolVerifier is a contract that verifies that the SpokePool exists on this chain before sending ETH to it.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/SpokePoolVerifier.sol\":\"SpokePoolVerifier\"},\"debug\":{\"revertStrings\":\"strip\"},\"evmVersion\":\"paris\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":1000000},\"remappings\":[],\"viaIR\":true},\"sources\":{\"@openzeppelin/contracts/utils/Address.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.9.0) (utils/Address.sol)\\n\\npragma solidity ^0.8.1;\\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 * Furthermore, `isContract` will also return true if the target contract within\\n * the same transaction is already scheduled for destruction by `SELFDESTRUCT`,\\n * which only has an effect at the end of a transaction.\\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 > 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://consensys.net/diligence/blog/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.8.0/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\\n */\\n function sendValue(address payable recipient, uint256 amount) internal {\\n require(address(this).balance >= amount, \\\"Address: insufficient balance\\\");\\n\\n (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 functionCallWithValue(target, data, 0, \\\"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(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, value, \\\"Address: low-level call with value failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\\n * with `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(address(this).balance >= value, \\\"Address: insufficient balance for call\\\");\\n (bool success, bytes memory returndata) = target.call{value: value}(data);\\n return verifyCallResultFromTarget(target, 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 (bool success, bytes memory returndata) = target.staticcall(data);\\n return verifyCallResultFromTarget(target, 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 (bool success, bytes memory returndata) = target.delegatecall(data);\\n return verifyCallResultFromTarget(target, success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling\\n * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.\\n *\\n * _Available since v4.8._\\n */\\n function verifyCallResultFromTarget(\\n address target,\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n if (success) {\\n if (returndata.length == 0) {\\n // only check isContract if the call was successful and the return data is empty\\n // otherwise we already know that it was a contract\\n require(isContract(target), \\\"Address: call to non-contract\\\");\\n }\\n return returndata;\\n } else {\\n _revert(returndata, errorMessage);\\n }\\n }\\n\\n /**\\n * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the\\n * revert reason or 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 _revert(returndata, errorMessage);\\n }\\n }\\n\\n function _revert(bytes memory returndata, string memory errorMessage) private pure {\\n // Look for revert reason and bubble it up if present\\n if (returndata.length > 0) {\\n // The easiest way to bubble the revert reason is using memory via assembly\\n /// @solidity memory-safe-assembly\\n assembly {\\n let returndata_size := mload(returndata)\\n revert(add(32, returndata), returndata_size)\\n }\\n } else {\\n revert(errorMessage);\\n }\\n }\\n}\\n\",\"keccak256\":\"0x006dd67219697fe68d7fbfdea512e7c4cb64a43565ed86171d67e844982da6fa\",\"license\":\"MIT\"},\"contracts/SpokePoolVerifier.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\nimport \\\"@openzeppelin/contracts/utils/Address.sol\\\";\\nimport \\\"./interfaces/SpokePoolInterface.sol\\\";\\n\\n/**\\n * @notice SpokePoolVerifier is a contract that verifies that the SpokePool exists on this chain before sending ETH to it.\\n * @dev This contract must be deployed via Create2 to the same address on all chains. That way, an errant transaction sent\\n * to the wrong chain will be blocked by this contract rather than hitting a dead address. This means that this contract\\n * will not work to protect chains, like zkSync, where Create2 address derivations don't match other chains.\\n * Source: https://era.zksync.io/docs/reference/architecture/differences-with-ethereum.html#create-create2\\n */\\ncontract SpokePoolVerifier {\\n using Address for address;\\n\\n /**\\n * @notice Passthrough function to `depositV3()` on the SpokePool contract.\\n * @dev Protects the caller from losing their ETH (or other native token) by reverting if the SpokePool address\\n * they intended to call does not exist on this chain. Because this contract can be deployed at the same address\\n * everywhere callers should be protected even if the transaction is submitted to an unintended network.\\n * This contract should only be used for native token deposits, as this problem only exists for native tokens.\\n * @param spokePool Address of the SpokePool contract that the user is intending to call.\\n * @param recipient Address to receive funds at on destination chain.\\n * @param originToken Token to lock into this contract to initiate deposit.\\n * @param amount Amount of tokens to deposit. Will be amount of tokens to receive less fees.\\n * @param destinationChainId Denotes network where user will receive funds from SpokePool by a relayer.\\n * @param relayerFeePct % of deposit amount taken out to incentivize a fast relayer.\\n * @param quoteTimestamp Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid\\n * to LP pool on HubPool.\\n * @param message Arbitrary data that can be used to pass additional information to the recipient along with the tokens.\\n * Note: this is intended to be used to pass along instructions for how a contract should use or allocate the tokens.\\n * @param maxCount used to protect the depositor from frontrunning to guarantee their quote remains valid.\\n * Note: this is intended to be used to pass along instructions for how a contract should use or allocate the tokens.\\n */\\n function deposit(\\n SpokePoolInterface spokePool,\\n address recipient,\\n address originToken,\\n uint256 amount,\\n uint256 destinationChainId,\\n int64 relayerFeePct,\\n uint32 quoteTimestamp,\\n bytes memory message,\\n uint256 maxCount\\n ) external payable {\\n require(msg.value == amount, \\\"msg.value != amount\\\");\\n require(address(spokePool).isContract(), \\\"spokePool is not a contract\\\");\\n // Set msg.sender as the depositor so that msg.sender can speed up the deposit.\\n spokePool.depositFor{ value: msg.value }(\\n msg.sender,\\n recipient,\\n originToken,\\n amount,\\n destinationChainId,\\n relayerFeePct,\\n quoteTimestamp,\\n message,\\n maxCount\\n );\\n }\\n}\\n\",\"keccak256\":\"0xfc008c31a2fde7eb0daedaa823b76931225f41ac882b6d1c515d8a38ccda60ec\",\"license\":\"BUSL-1.1\"},\"contracts/interfaces/SpokePoolInterface.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\n/**\\n * @notice Contains common data structures and functions used by all SpokePool implementations.\\n */\\ninterface SpokePoolInterface {\\n // This leaf is meant to be decoded in the SpokePool to pay out successful relayers.\\n struct RelayerRefundLeaf {\\n // This is the amount to return to the HubPool. This occurs when there is a PoolRebalanceLeaf netSendAmount that\\n // is negative. This is just the negative of this value.\\n uint256 amountToReturn;\\n // Used to verify that this is being executed on the correct destination chainId.\\n uint256 chainId;\\n // This array designates how much each of those addresses should be refunded.\\n uint256[] refundAmounts;\\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\\n uint32 leafId;\\n // The associated L2TokenAddress that these claims apply to.\\n address l2TokenAddress;\\n // Must be same length as refundAmounts and designates each address that must be refunded.\\n address[] refundAddresses;\\n }\\n\\n // Stores collection of merkle roots that can be published to this contract from the HubPool, which are referenced\\n // by \\\"data workers\\\" via inclusion proofs to execute leaves in the roots.\\n struct RootBundle {\\n // Merkle root of slow relays that were not fully filled and whose recipient is still owed funds from the LP pool.\\n bytes32 slowRelayRoot;\\n // Merkle root of relayer refunds for successful relays.\\n bytes32 relayerRefundRoot;\\n // This is a 2D bitmap tracking which leaves in the relayer refund root have been claimed, with max size of\\n // 256x(2^248) leaves per root.\\n mapping(uint256 => uint256) claimedBitmap;\\n }\\n\\n function setCrossDomainAdmin(address newCrossDomainAdmin) external;\\n\\n function setHubPool(address newHubPool) external;\\n\\n function setEnableRoute(\\n address originToken,\\n uint256 destinationChainId,\\n bool enable\\n ) external;\\n\\n function pauseDeposits(bool pause) external;\\n\\n function pauseFills(bool pause) external;\\n\\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) external;\\n\\n function emergencyDeleteRootBundle(uint256 rootBundleId) external;\\n\\n function deposit(\\n address recipient,\\n address originToken,\\n uint256 amount,\\n uint256 destinationChainId,\\n int64 relayerFeePct,\\n uint32 quoteTimestamp,\\n bytes memory message,\\n uint256 maxCount\\n ) external payable;\\n\\n function depositFor(\\n address depositor,\\n address recipient,\\n address originToken,\\n uint256 amount,\\n uint256 destinationChainId,\\n int64 relayerFeePct,\\n uint32 quoteTimestamp,\\n bytes memory message,\\n uint256 maxCount\\n ) external payable;\\n\\n function executeRelayerRefundLeaf(\\n uint32 rootBundleId,\\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\\n bytes32[] memory proof\\n ) external payable;\\n\\n function chainId() external view returns (uint256);\\n\\n error NotEOA();\\n error InvalidDepositorSignature();\\n error InvalidRelayerFeePct();\\n error MaxTransferSizeExceeded();\\n error InvalidCrossDomainAdmin();\\n error InvalidHubPool();\\n error DepositsArePaused();\\n error FillsArePaused();\\n}\\n\",\"keccak256\":\"0xc90fbd7e66e2e87e9aacbe93c20cc020cd1fc582c4fd4879807e7dc026943ea0\",\"license\":\"BUSL-1.1\"}},\"version\":1}", - "bytecode": "0x608080604052346100165761034b908161001c8239f35b600080fdfe600436101561000d57600080fd5b6000803560e01c63e0db3fcf1461002357600080fd5b610120807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103115773ffffffffffffffffffffffffffffffffffffffff600435818116810361030d576024359282841684036103095760443583811681036103055760a4358060070b81036103015760c4359063ffffffff8216820361029b5760e43567ffffffffffffffff81116102fd57366023820112156102fd57806004013567ffffffffffffffff81116102d0577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0603f81601f84011601166080016080811067ffffffffffffffff8211176102a357908a929160405280608052366024828401011161029f57602091819060240160a0376080010152606435340361029b578585163b1561029b578585163b1561029b57859694929163ffffffff91878a9896946040519a8b997f541f4f14000000000000000000000000000000000000000000000000000000008b523360048c01521660248a01521660448801526064356064880152608435608488015260070b60a48701521660c485015260e484015260805180610124850152845b8181106102805750908391827fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f6101449389858286010152610104803590850152011681010301923491165af1801561027557610233575080f35b67ffffffffffffffff81116102485760405280f35b6024827f4e487b710000000000000000000000000000000000000000000000000000000081526041600452fd5b6040513d84823e3d90fd5b60a081015187820161014401528795508694506020016101d6565b8780fd5b8280fd5b60248b7f4e487b710000000000000000000000000000000000000000000000000000000081526041600452fd5b60248a7f4e487b710000000000000000000000000000000000000000000000000000000081526041600452fd5b8880fd5b8680fd5b8580fd5b8480fd5b8380fd5b5080fdfea26469706673582212204f81f550f00970671d0755020f959a6599fd76306000e67b424172e1089b949a64736f6c63430008130033", - "deployedBytecode": "0x600436101561000d57600080fd5b6000803560e01c63e0db3fcf1461002357600080fd5b610120807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103115773ffffffffffffffffffffffffffffffffffffffff600435818116810361030d576024359282841684036103095760443583811681036103055760a4358060070b81036103015760c4359063ffffffff8216820361029b5760e43567ffffffffffffffff81116102fd57366023820112156102fd57806004013567ffffffffffffffff81116102d0577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0603f81601f84011601166080016080811067ffffffffffffffff8211176102a357908a929160405280608052366024828401011161029f57602091819060240160a0376080010152606435340361029b578585163b1561029b578585163b1561029b57859694929163ffffffff91878a9896946040519a8b997f541f4f14000000000000000000000000000000000000000000000000000000008b523360048c01521660248a01521660448801526064356064880152608435608488015260070b60a48701521660c485015260e484015260805180610124850152845b8181106102805750908391827fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f6101449389858286010152610104803590850152011681010301923491165af1801561027557610233575080f35b67ffffffffffffffff81116102485760405280f35b6024827f4e487b710000000000000000000000000000000000000000000000000000000081526041600452fd5b6040513d84823e3d90fd5b60a081015187820161014401528795508694506020016101d6565b8780fd5b8280fd5b60248b7f4e487b710000000000000000000000000000000000000000000000000000000081526041600452fd5b60248a7f4e487b710000000000000000000000000000000000000000000000000000000081526041600452fd5b8880fd5b8680fd5b8580fd5b8480fd5b8380fd5b5080fdfea26469706673582212204f81f550f00970671d0755020f959a6599fd76306000e67b424172e1089b949a64736f6c63430008130033", + "numDeployments": 3, + "solcInputHash": "783274f805324492b21545b62eb0dbfe", + "metadata": "{\"compiler\":{\"version\":\"0.8.19+commit.7dd6d404\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"contract V3SpokePoolInterface\",\"name\":\"spokePool\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"inputToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"inputAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"outputAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"exclusiveRelayer\",\"type\":\"address\"},{\"internalType\":\"uint32\",\"name\":\"quoteTimestamp\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"fillDeadline\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"exclusivityDeadline\",\"type\":\"uint32\"},{\"internalType\":\"bytes\",\"name\":\"message\",\"type\":\"bytes\"}],\"name\":\"deposit\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"}],\"devdoc\":{\"custom:security-contact\":\"bugs@across.to\",\"details\":\"This contract must be deployed via Create2 to the same address on all chains. That way, an errant transaction sent to the wrong chain will be blocked by this contract rather than hitting a dead address. This means that this contract will not work to protect chains, like zkSync, where Create2 address derivations don't match other chains. Source: https://era.zksync.io/docs/reference/architecture/differences-with-ethereum.html#create-create2\",\"kind\":\"dev\",\"methods\":{\"deposit(address,address,address,uint256,uint256,uint256,address,uint32,uint32,uint32,bytes)\":{\"details\":\"Protects the caller from losing their ETH (or other native token) by reverting if the SpokePool address they intended to call does not exist on this chain. Because this contract can be deployed at the same address everywhere callers should be protected even if the transaction is submitted to an unintended network. This contract should only be used for native token deposits, as this problem only exists for native tokens.\",\"params\":{\"destinationChainId\":\"Denotes network where user will receive funds from SpokePool by a relayer.\",\"exclusiveRelayer\":\"Address of the relayer who has exclusive rights to fill this deposit. Can be set to 0x0 if no exclusivity period is desired. If so, then must set exclusivityDeadline to 0.\",\"exclusivityDeadline\":\"Timestamp after which any relayer can fill this deposit. Must set to 0 if exclusiveRelayer is set to 0x0, and vice versa.\",\"fillDeadline\":\"Timestamp after which this deposit can no longer be filled.\",\"inputAmount\":\"Amount of tokens to deposit.\",\"inputToken\":\"Token to lock into this contract to initiate deposit.\",\"message\":\"Arbitrary data that can be used to pass additional information to the recipient along with the tokens. Note: this is intended to be used to pass along instructions for how a contract should use or allocate the tokens.\",\"outputAmount\":\"Amount of tokens to receive on destination chain.\",\"quoteTimestamp\":\"Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid to LP pool on HubPool.\",\"recipient\":\"Address to receive funds at on destination chain.\",\"spokePool\":\"Address of the SpokePool contract that the user is intending to call.\"}}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"deposit(address,address,address,uint256,uint256,uint256,address,uint32,uint32,uint32,bytes)\":{\"notice\":\"Passthrough function to `depositV3()` on the SpokePool contract.\"}},\"notice\":\"SpokePoolVerifier is a contract that verifies that the SpokePool exists on this chain before sending ETH to it.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/SpokePoolVerifier.sol\":\"SpokePoolVerifier\"},\"debug\":{\"revertStrings\":\"strip\"},\"evmVersion\":\"paris\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":1000000},\"remappings\":[],\"viaIR\":true},\"sources\":{\"@openzeppelin/contracts/utils/Address.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.9.0) (utils/Address.sol)\\n\\npragma solidity ^0.8.1;\\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 * Furthermore, `isContract` will also return true if the target contract within\\n * the same transaction is already scheduled for destruction by `SELFDESTRUCT`,\\n * which only has an effect at the end of a transaction.\\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 > 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://consensys.net/diligence/blog/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.8.0/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\\n */\\n function sendValue(address payable recipient, uint256 amount) internal {\\n require(address(this).balance >= amount, \\\"Address: insufficient balance\\\");\\n\\n (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 functionCallWithValue(target, data, 0, \\\"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(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, value, \\\"Address: low-level call with value failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\\n * with `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(address(this).balance >= value, \\\"Address: insufficient balance for call\\\");\\n (bool success, bytes memory returndata) = target.call{value: value}(data);\\n return verifyCallResultFromTarget(target, 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 (bool success, bytes memory returndata) = target.staticcall(data);\\n return verifyCallResultFromTarget(target, 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 (bool success, bytes memory returndata) = target.delegatecall(data);\\n return verifyCallResultFromTarget(target, success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling\\n * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.\\n *\\n * _Available since v4.8._\\n */\\n function verifyCallResultFromTarget(\\n address target,\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n if (success) {\\n if (returndata.length == 0) {\\n // only check isContract if the call was successful and the return data is empty\\n // otherwise we already know that it was a contract\\n require(isContract(target), \\\"Address: call to non-contract\\\");\\n }\\n return returndata;\\n } else {\\n _revert(returndata, errorMessage);\\n }\\n }\\n\\n /**\\n * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the\\n * revert reason or 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 _revert(returndata, errorMessage);\\n }\\n }\\n\\n function _revert(bytes memory returndata, string memory errorMessage) private pure {\\n // Look for revert reason and bubble it up if present\\n if (returndata.length > 0) {\\n // The easiest way to bubble the revert reason is using memory via assembly\\n /// @solidity memory-safe-assembly\\n assembly {\\n let returndata_size := mload(returndata)\\n revert(add(32, returndata), returndata_size)\\n }\\n } else {\\n revert(errorMessage);\\n }\\n }\\n}\\n\",\"keccak256\":\"0x006dd67219697fe68d7fbfdea512e7c4cb64a43565ed86171d67e844982da6fa\",\"license\":\"MIT\"},\"contracts/SpokePoolVerifier.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\nimport \\\"@openzeppelin/contracts/utils/Address.sol\\\";\\nimport \\\"./interfaces/V3SpokePoolInterface.sol\\\";\\n\\n/**\\n * @notice SpokePoolVerifier is a contract that verifies that the SpokePool exists on this chain before sending ETH to it.\\n * @dev This contract must be deployed via Create2 to the same address on all chains. That way, an errant transaction sent\\n * to the wrong chain will be blocked by this contract rather than hitting a dead address. This means that this contract\\n * will not work to protect chains, like zkSync, where Create2 address derivations don't match other chains.\\n * Source: https://era.zksync.io/docs/reference/architecture/differences-with-ethereum.html#create-create2\\n * @custom:security-contact bugs@across.to\\n */\\ncontract SpokePoolVerifier {\\n using Address for address;\\n\\n /**\\n * @notice Passthrough function to `depositV3()` on the SpokePool contract.\\n * @dev Protects the caller from losing their ETH (or other native token) by reverting if the SpokePool address\\n * they intended to call does not exist on this chain. Because this contract can be deployed at the same address\\n * everywhere callers should be protected even if the transaction is submitted to an unintended network.\\n * This contract should only be used for native token deposits, as this problem only exists for native tokens.\\n * @param spokePool Address of the SpokePool contract that the user is intending to call.\\n * @param recipient Address to receive funds at on destination chain.\\n * @param inputToken Token to lock into this contract to initiate deposit.\\n * @param inputAmount Amount of tokens to deposit.\\n * @param outputAmount Amount of tokens to receive on destination chain.\\n * @param destinationChainId Denotes network where user will receive funds from SpokePool by a relayer.\\n * @param quoteTimestamp Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid\\n * to LP pool on HubPool.\\n * @param message Arbitrary data that can be used to pass additional information to the recipient along with the tokens.\\n * Note: this is intended to be used to pass along instructions for how a contract should use or allocate the tokens.\\n * @param exclusiveRelayer Address of the relayer who has exclusive rights to fill this deposit. Can be set to\\n * 0x0 if no exclusivity period is desired. If so, then must set exclusivityDeadline to 0.\\n * @param exclusivityDeadline Timestamp after which any relayer can fill this deposit. Must set\\n * to 0 if exclusiveRelayer is set to 0x0, and vice versa.\\n * @param fillDeadline Timestamp after which this deposit can no longer be filled.\\n */\\n function deposit(\\n V3SpokePoolInterface spokePool,\\n address recipient,\\n address inputToken,\\n uint256 inputAmount,\\n uint256 outputAmount,\\n uint256 destinationChainId,\\n address exclusiveRelayer,\\n uint32 quoteTimestamp,\\n uint32 fillDeadline,\\n uint32 exclusivityDeadline,\\n bytes memory message\\n ) external payable {\\n require(msg.value == inputAmount, \\\"msg.value != amount\\\");\\n require(address(spokePool).isContract(), \\\"spokePool is not a contract\\\");\\n // Set msg.sender as the depositor so that msg.sender can speed up the deposit.\\n spokePool.depositV3{ value: msg.value }(\\n msg.sender,\\n recipient,\\n inputToken,\\n // @dev Setting outputToken to 0x0 to instruct fillers to use the equivalent token\\n // as the originToken on the destination chain.\\n address(0),\\n inputAmount,\\n outputAmount,\\n destinationChainId,\\n exclusiveRelayer,\\n quoteTimestamp,\\n fillDeadline,\\n exclusivityDeadline,\\n message\\n );\\n }\\n}\\n\",\"keccak256\":\"0xd5b1ec1b7048634a8b0a7e1e2c68ce51e410157b14778a207b64aff49bc5c6f0\",\"license\":\"BUSL-1.1\"},\"contracts/interfaces/V3SpokePoolInterface.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\n// Contains structs and functions used by SpokePool contracts to facilitate universal settlement.\\ninterface V3SpokePoolInterface {\\n /**************************************\\n * ENUMS *\\n **************************************/\\n\\n // Fill status tracks on-chain state of deposit, uniquely identified by relayHash.\\n enum FillStatus {\\n Unfilled,\\n RequestedSlowFill,\\n Filled\\n }\\n // Fill type is emitted in the FilledRelay event to assist Dataworker with determining which types of\\n // fills to refund (e.g. only fast fills) and whether a fast fill created a sow fill excess.\\n enum FillType {\\n FastFill,\\n // Fast fills are normal fills that do not replace a slow fill request.\\n ReplacedSlowFill,\\n // Replaced slow fills are fast fills that replace a slow fill request. This type is used by the Dataworker\\n // to know when to send excess funds from the SpokePool to the HubPool because they can no longer be used\\n // for a slow fill execution.\\n SlowFill\\n // Slow fills are requested via requestSlowFill and executed by executeSlowRelayLeaf after a bundle containing\\n // the slow fill is validated.\\n }\\n\\n /**************************************\\n * STRUCTS *\\n **************************************/\\n\\n // This struct represents the data to fully specify a **unique** relay submitted on this chain.\\n // This data is hashed with the chainId() and saved by the SpokePool to prevent collisions and protect against\\n // replay attacks on other chains. If any portion of this data differs, the relay is considered to be\\n // completely distinct.\\n struct V3RelayData {\\n // The address that made the deposit on the origin chain.\\n address depositor;\\n // The recipient address on the destination chain.\\n address recipient;\\n // This is the exclusive relayer who can fill the deposit before the exclusivity deadline.\\n address exclusiveRelayer;\\n // Token that is deposited on origin chain by depositor.\\n address inputToken;\\n // Token that is received on destination chain by recipient.\\n address outputToken;\\n // The amount of input token deposited by depositor.\\n uint256 inputAmount;\\n // The amount of output token to be received by recipient.\\n uint256 outputAmount;\\n // Origin chain id.\\n uint256 originChainId;\\n // The id uniquely identifying this deposit on the origin chain.\\n uint32 depositId;\\n // The timestamp on the destination chain after which this deposit can no longer be filled.\\n uint32 fillDeadline;\\n // The timestamp on the destination chain after which any relayer can fill the deposit.\\n uint32 exclusivityDeadline;\\n // Data that is forwarded to the recipient.\\n bytes message;\\n }\\n\\n // Contains parameters passed in by someone who wants to execute a slow relay leaf.\\n struct V3SlowFill {\\n V3RelayData relayData;\\n uint256 chainId;\\n uint256 updatedOutputAmount;\\n }\\n\\n // Contains information about a relay to be sent along with additional information that is not unique to the\\n // relay itself but is required to know how to process the relay. For example, \\\"updatedX\\\" fields can be used\\n // by the relayer to modify fields of the relay with the depositor's permission, and \\\"repaymentChainId\\\" is specified\\n // by the relayer to determine where to take a relayer refund, but doesn't affect the uniqueness of the relay.\\n struct V3RelayExecutionParams {\\n V3RelayData relay;\\n bytes32 relayHash;\\n uint256 updatedOutputAmount;\\n address updatedRecipient;\\n bytes updatedMessage;\\n uint256 repaymentChainId;\\n }\\n\\n // Packs together parameters emitted in FilledV3Relay because there are too many emitted otherwise.\\n // Similar to V3RelayExecutionParams, these parameters are not used to uniquely identify the deposit being\\n // filled so they don't have to be unpacked by all clients.\\n struct V3RelayExecutionEventInfo {\\n address updatedRecipient;\\n bytes updatedMessage;\\n uint256 updatedOutputAmount;\\n FillType fillType;\\n }\\n\\n /**************************************\\n * EVENTS *\\n **************************************/\\n\\n event V3FundsDeposited(\\n address inputToken,\\n address outputToken,\\n uint256 inputAmount,\\n uint256 outputAmount,\\n uint256 indexed destinationChainId,\\n uint32 indexed depositId,\\n uint32 quoteTimestamp,\\n uint32 fillDeadline,\\n uint32 exclusivityDeadline,\\n address indexed depositor,\\n address recipient,\\n address exclusiveRelayer,\\n bytes message\\n );\\n\\n event RequestedSpeedUpV3Deposit(\\n uint256 updatedOutputAmount,\\n uint32 indexed depositId,\\n address indexed depositor,\\n address updatedRecipient,\\n bytes updatedMessage,\\n bytes depositorSignature\\n );\\n\\n event FilledV3Relay(\\n address inputToken,\\n address outputToken,\\n uint256 inputAmount,\\n uint256 outputAmount,\\n uint256 repaymentChainId,\\n uint256 indexed originChainId,\\n uint32 indexed depositId,\\n uint32 fillDeadline,\\n uint32 exclusivityDeadline,\\n address exclusiveRelayer,\\n address indexed relayer,\\n address depositor,\\n address recipient,\\n bytes message,\\n V3RelayExecutionEventInfo relayExecutionInfo\\n );\\n\\n event RequestedV3SlowFill(\\n address inputToken,\\n address outputToken,\\n uint256 inputAmount,\\n uint256 outputAmount,\\n uint256 indexed originChainId,\\n uint32 indexed depositId,\\n uint32 fillDeadline,\\n uint32 exclusivityDeadline,\\n address exclusiveRelayer,\\n address depositor,\\n address recipient,\\n bytes message\\n );\\n\\n /**************************************\\n * FUNCTIONS *\\n **************************************/\\n\\n function depositV3(\\n address depositor,\\n address recipient,\\n address inputToken,\\n address outputToken,\\n uint256 inputAmount,\\n uint256 outputAmount,\\n uint256 destinationChainId,\\n address exclusiveRelayer,\\n uint32 quoteTimestamp,\\n uint32 fillDeadline,\\n uint32 exclusivityDeadline,\\n bytes calldata message\\n ) external payable;\\n\\n function depositV3Now(\\n address depositor,\\n address recipient,\\n address inputToken,\\n address outputToken,\\n uint256 inputAmount,\\n uint256 outputAmount,\\n uint256 destinationChainId,\\n address exclusiveRelayer,\\n uint32 fillDeadlineOffset,\\n uint32 exclusivityDeadline,\\n bytes calldata message\\n ) external payable;\\n\\n function speedUpV3Deposit(\\n address depositor,\\n uint32 depositId,\\n uint256 updatedOutputAmount,\\n address updatedRecipient,\\n bytes calldata updatedMessage,\\n bytes calldata depositorSignature\\n ) external;\\n\\n function fillV3Relay(V3RelayData calldata relayData, uint256 repaymentChainId) external;\\n\\n function fillV3RelayWithUpdatedDeposit(\\n V3RelayData calldata relayData,\\n uint256 repaymentChainId,\\n uint256 updatedOutputAmount,\\n address updatedRecipient,\\n bytes calldata updatedMessage,\\n bytes calldata depositorSignature\\n ) external;\\n\\n function requestV3SlowFill(V3RelayData calldata relayData) external;\\n\\n function executeV3SlowRelayLeaf(\\n V3SlowFill calldata slowFillLeaf,\\n uint32 rootBundleId,\\n bytes32[] calldata proof\\n ) external;\\n\\n /**************************************\\n * ERRORS *\\n **************************************/\\n\\n error DisabledRoute();\\n error InvalidQuoteTimestamp();\\n error InvalidFillDeadline();\\n error InvalidExclusiveRelayer();\\n error InvalidExclusivityDeadline();\\n error MsgValueDoesNotMatchInputAmount();\\n error NotExclusiveRelayer();\\n error NoSlowFillsInExclusivityWindow();\\n error RelayFilled();\\n error InvalidSlowFillRequest();\\n error ExpiredFillDeadline();\\n error InvalidMerkleProof();\\n error InvalidChainId();\\n error InvalidMerkleLeaf();\\n error ClaimedMerkleLeaf();\\n error InvalidPayoutAdjustmentPct();\\n}\\n\",\"keccak256\":\"0x374b7e9cb8afbcaec69cdbcde480676b5d927db84c7f38221331d1226af68d9d\",\"license\":\"BUSL-1.1\"}},\"version\":1}", + "bytecode": "0x60808060405234610016576103a4908161001c8239f35b600080fdfe600436101561000d57600080fd5b6000803560e01c63902e949c1461002357600080fd5b6101607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261036b5773ffffffffffffffffffffffffffffffffffffffff6004358181168103610367576024359082821682036103635760443591838316830361035f5760c435848116810361035b5760e4359063ffffffff928383168303610357576101043590848216820361035357610124359385851685036103225767ffffffffffffffff610144351161032257366023610144350112156103225767ffffffffffffffff6101443560040135116103265767ffffffffffffffff6004610144350135601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f0116608090810191821191101761032657608060046101443590810135601f81017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f011683016040529182905236910160240111610322576101443560048101359060240160a03760a06004610144350135018a90526064353403610322578887163b15610322578887163b1561032257918589979593888296818e9c60409e9b979e519e8f9d8e917f7b9392320000000000000000000000000000000000000000000000000000000083523360048401521690602401521660448c01528b60648c015260643560848c015260843560a48c015260a43560c48c01521660e48a01521661010488015216610124860152166101448401526101648301610180905260805180610184850152845b8181106103075750908391827fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f6101a49389858286010152011681010301923491165af180156102fc576102ba575080f35b67ffffffffffffffff81116102cf5760405280f35b6024827f4e487b710000000000000000000000000000000000000000000000000000000081526041600452fd5b6040513d84823e3d90fd5b60a08101518782016101a40152879550869450602001610266565b8980fd5b60248a7f4e487b710000000000000000000000000000000000000000000000000000000081526041600452fd5b8880fd5b8780fd5b8580fd5b8480fd5b8380fd5b8280fd5b80fdfea26469706673582212201ceff237e6adbd0d3f92e892f7f3f51306c23eac5f7e3f896c2c723d9e5be3a664736f6c63430008130033", + "deployedBytecode": "0x600436101561000d57600080fd5b6000803560e01c63902e949c1461002357600080fd5b6101607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261036b5773ffffffffffffffffffffffffffffffffffffffff6004358181168103610367576024359082821682036103635760443591838316830361035f5760c435848116810361035b5760e4359063ffffffff928383168303610357576101043590848216820361035357610124359385851685036103225767ffffffffffffffff610144351161032257366023610144350112156103225767ffffffffffffffff6101443560040135116103265767ffffffffffffffff6004610144350135601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f0116608090810191821191101761032657608060046101443590810135601f81017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f011683016040529182905236910160240111610322576101443560048101359060240160a03760a06004610144350135018a90526064353403610322578887163b15610322578887163b1561032257918589979593888296818e9c60409e9b979e519e8f9d8e917f7b9392320000000000000000000000000000000000000000000000000000000083523360048401521690602401521660448c01528b60648c015260643560848c015260843560a48c015260a43560c48c01521660e48a01521661010488015216610124860152166101448401526101648301610180905260805180610184850152845b8181106103075750908391827fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f6101a49389858286010152011681010301923491165af180156102fc576102ba575080f35b67ffffffffffffffff81116102cf5760405280f35b6024827f4e487b710000000000000000000000000000000000000000000000000000000081526041600452fd5b6040513d84823e3d90fd5b60a08101518782016101a40152879550869450602001610266565b8980fd5b60248a7f4e487b710000000000000000000000000000000000000000000000000000000081526041600452fd5b8880fd5b8780fd5b8580fd5b8480fd5b8380fd5b8280fd5b80fdfea26469706673582212201ceff237e6adbd0d3f92e892f7f3f51306c23eac5f7e3f896c2c723d9e5be3a664736f6c63430008130033", "devdoc": { + "custom:security-contact": "bugs@across.to", "details": "This contract must be deployed via Create2 to the same address on all chains. That way, an errant transaction sent to the wrong chain will be blocked by this contract rather than hitting a dead address. This means that this contract will not work to protect chains, like zkSync, where Create2 address derivations don't match other chains. Source: https://era.zksync.io/docs/reference/architecture/differences-with-ethereum.html#create-create2", "kind": "dev", "methods": { - "deposit(address,address,address,uint256,uint256,int64,uint32,bytes,uint256)": { + "deposit(address,address,address,uint256,uint256,uint256,address,uint32,uint32,uint32,bytes)": { "details": "Protects the caller from losing their ETH (or other native token) by reverting if the SpokePool address they intended to call does not exist on this chain. Because this contract can be deployed at the same address everywhere callers should be protected even if the transaction is submitted to an unintended network. This contract should only be used for native token deposits, as this problem only exists for native tokens.", "params": { - "amount": "Amount of tokens to deposit. Will be amount of tokens to receive less fees.", "destinationChainId": "Denotes network where user will receive funds from SpokePool by a relayer.", - "maxCount": "used to protect the depositor from frontrunning to guarantee their quote remains valid. Note: this is intended to be used to pass along instructions for how a contract should use or allocate the tokens.", + "exclusiveRelayer": "Address of the relayer who has exclusive rights to fill this deposit. Can be set to 0x0 if no exclusivity period is desired. If so, then must set exclusivityDeadline to 0.", + "exclusivityDeadline": "Timestamp after which any relayer can fill this deposit. Must set to 0 if exclusiveRelayer is set to 0x0, and vice versa.", + "fillDeadline": "Timestamp after which this deposit can no longer be filled.", + "inputAmount": "Amount of tokens to deposit.", + "inputToken": "Token to lock into this contract to initiate deposit.", "message": "Arbitrary data that can be used to pass additional information to the recipient along with the tokens. Note: this is intended to be used to pass along instructions for how a contract should use or allocate the tokens.", - "originToken": "Token to lock into this contract to initiate deposit.", + "outputAmount": "Amount of tokens to receive on destination chain.", "quoteTimestamp": "Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid to LP pool on HubPool.", "recipient": "Address to receive funds at on destination chain.", - "relayerFeePct": "% of deposit amount taken out to incentivize a fast relayer.", "spokePool": "Address of the SpokePool contract that the user is intending to call." } } @@ -101,7 +114,7 @@ "userdoc": { "kind": "user", "methods": { - "deposit(address,address,address,uint256,uint256,int64,uint32,bytes,uint256)": { + "deposit(address,address,address,uint256,uint256,uint256,address,uint32,uint32,uint32,bytes)": { "notice": "Passthrough function to `depositV3()` on the SpokePool contract." } }, diff --git a/deployments/linea/solcInputs/1a67233dfe969c05446730f26ab1d2c8.json b/deployments/linea/solcInputs/1a67233dfe969c05446730f26ab1d2c8.json new file mode 100644 index 000000000..96daeb1aa --- /dev/null +++ b/deployments/linea/solcInputs/1a67233dfe969c05446730f26ab1d2c8.json @@ -0,0 +1,43 @@ +{ + "language": "Solidity", + "sources": { + "@openzeppelin/contracts/utils/Address.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (utils/Address.sol)\n\npragma solidity ^0.8.1;\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 * Furthermore, `isContract` will also return true if the target contract within\n * the same transaction is already scheduled for destruction by `SELFDESTRUCT`,\n * which only has an effect at the end of a transaction.\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 > 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://consensys.net/diligence/blog/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.8.0/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n require(address(this).balance >= amount, \"Address: insufficient balance\");\n\n (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 functionCallWithValue(target, data, 0, \"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(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n return functionCallWithValue(target, data, value, \"Address: low-level call with value failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\n * with `errorMessage` as a fallback revert reason when `target` reverts.\n *\n * _Available since v3.1._\n */\n function functionCallWithValue(\n address target,\n bytes memory data,\n uint256 value,\n string memory errorMessage\n ) internal returns (bytes memory) {\n require(address(this).balance >= value, \"Address: insufficient balance for call\");\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, 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 (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, 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 (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata, errorMessage);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling\n * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.\n *\n * _Available since v4.8._\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata,\n string memory errorMessage\n ) internal view returns (bytes memory) {\n if (success) {\n if (returndata.length == 0) {\n // only check isContract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n require(isContract(target), \"Address: call to non-contract\");\n }\n return returndata;\n } else {\n _revert(returndata, errorMessage);\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the\n * revert reason or 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 _revert(returndata, errorMessage);\n }\n }\n\n function _revert(bytes memory returndata, string memory errorMessage) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length > 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert(errorMessage);\n }\n }\n}\n" + }, + "contracts/interfaces/V3SpokePoolInterface.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n// Contains structs and functions used by SpokePool contracts to facilitate universal settlement.\ninterface V3SpokePoolInterface {\n /**************************************\n * ENUMS *\n **************************************/\n\n // Fill status tracks on-chain state of deposit, uniquely identified by relayHash.\n enum FillStatus {\n Unfilled,\n RequestedSlowFill,\n Filled\n }\n // Fill type is emitted in the FilledRelay event to assist Dataworker with determining which types of\n // fills to refund (e.g. only fast fills) and whether a fast fill created a sow fill excess.\n enum FillType {\n FastFill,\n // Fast fills are normal fills that do not replace a slow fill request.\n ReplacedSlowFill,\n // Replaced slow fills are fast fills that replace a slow fill request. This type is used by the Dataworker\n // to know when to send excess funds from the SpokePool to the HubPool because they can no longer be used\n // for a slow fill execution.\n SlowFill\n // Slow fills are requested via requestSlowFill and executed by executeSlowRelayLeaf after a bundle containing\n // the slow fill is validated.\n }\n\n /**************************************\n * STRUCTS *\n **************************************/\n\n // This struct represents the data to fully specify a **unique** relay submitted on this chain.\n // This data is hashed with the chainId() and saved by the SpokePool to prevent collisions and protect against\n // replay attacks on other chains. If any portion of this data differs, the relay is considered to be\n // completely distinct.\n struct V3RelayData {\n // The address that made the deposit on the origin chain.\n address depositor;\n // The recipient address on the destination chain.\n address recipient;\n // This is the exclusive relayer who can fill the deposit before the exclusivity deadline.\n address exclusiveRelayer;\n // Token that is deposited on origin chain by depositor.\n address inputToken;\n // Token that is received on destination chain by recipient.\n address outputToken;\n // The amount of input token deposited by depositor.\n uint256 inputAmount;\n // The amount of output token to be received by recipient.\n uint256 outputAmount;\n // Origin chain id.\n uint256 originChainId;\n // The id uniquely identifying this deposit on the origin chain.\n uint32 depositId;\n // The timestamp on the destination chain after which this deposit can no longer be filled.\n uint32 fillDeadline;\n // The timestamp on the destination chain after which any relayer can fill the deposit.\n uint32 exclusivityDeadline;\n // Data that is forwarded to the recipient.\n bytes message;\n }\n\n // Contains parameters passed in by someone who wants to execute a slow relay leaf.\n struct V3SlowFill {\n V3RelayData relayData;\n uint256 chainId;\n uint256 updatedOutputAmount;\n }\n\n // Contains information about a relay to be sent along with additional information that is not unique to the\n // relay itself but is required to know how to process the relay. For example, \"updatedX\" fields can be used\n // by the relayer to modify fields of the relay with the depositor's permission, and \"repaymentChainId\" is specified\n // by the relayer to determine where to take a relayer refund, but doesn't affect the uniqueness of the relay.\n struct V3RelayExecutionParams {\n V3RelayData relay;\n bytes32 relayHash;\n uint256 updatedOutputAmount;\n address updatedRecipient;\n bytes updatedMessage;\n uint256 repaymentChainId;\n }\n\n // Packs together parameters emitted in FilledV3Relay because there are too many emitted otherwise.\n // Similar to V3RelayExecutionParams, these parameters are not used to uniquely identify the deposit being\n // filled so they don't have to be unpacked by all clients.\n struct V3RelayExecutionEventInfo {\n address updatedRecipient;\n bytes updatedMessage;\n uint256 updatedOutputAmount;\n FillType fillType;\n }\n\n /**************************************\n * EVENTS *\n **************************************/\n\n event V3FundsDeposited(\n address inputToken,\n address outputToken,\n uint256 inputAmount,\n uint256 outputAmount,\n uint256 indexed destinationChainId,\n uint32 indexed depositId,\n uint32 quoteTimestamp,\n uint32 fillDeadline,\n uint32 exclusivityDeadline,\n address indexed depositor,\n address recipient,\n address exclusiveRelayer,\n bytes message\n );\n\n event RequestedSpeedUpV3Deposit(\n uint256 updatedOutputAmount,\n uint32 indexed depositId,\n address indexed depositor,\n address updatedRecipient,\n bytes updatedMessage,\n bytes depositorSignature\n );\n\n event FilledV3Relay(\n address inputToken,\n address outputToken,\n uint256 inputAmount,\n uint256 outputAmount,\n uint256 repaymentChainId,\n uint256 indexed originChainId,\n uint32 indexed depositId,\n uint32 fillDeadline,\n uint32 exclusivityDeadline,\n address exclusiveRelayer,\n address indexed relayer,\n address depositor,\n address recipient,\n bytes message,\n V3RelayExecutionEventInfo relayExecutionInfo\n );\n\n event RequestedV3SlowFill(\n address inputToken,\n address outputToken,\n uint256 inputAmount,\n uint256 outputAmount,\n uint256 indexed originChainId,\n uint32 indexed depositId,\n uint32 fillDeadline,\n uint32 exclusivityDeadline,\n address exclusiveRelayer,\n address depositor,\n address recipient,\n bytes message\n );\n\n /**************************************\n * FUNCTIONS *\n **************************************/\n\n function depositV3(\n address depositor,\n address recipient,\n address inputToken,\n address outputToken,\n uint256 inputAmount,\n uint256 outputAmount,\n uint256 destinationChainId,\n address exclusiveRelayer,\n uint32 quoteTimestamp,\n uint32 fillDeadline,\n uint32 exclusivityDeadline,\n bytes calldata message\n ) external payable;\n\n function depositV3Now(\n address depositor,\n address recipient,\n address inputToken,\n address outputToken,\n uint256 inputAmount,\n uint256 outputAmount,\n uint256 destinationChainId,\n address exclusiveRelayer,\n uint32 fillDeadlineOffset,\n uint32 exclusivityDeadline,\n bytes calldata message\n ) external payable;\n\n function speedUpV3Deposit(\n address depositor,\n uint32 depositId,\n uint256 updatedOutputAmount,\n address updatedRecipient,\n bytes calldata updatedMessage,\n bytes calldata depositorSignature\n ) external;\n\n function fillV3Relay(V3RelayData calldata relayData, uint256 repaymentChainId) external;\n\n function fillV3RelayWithUpdatedDeposit(\n V3RelayData calldata relayData,\n uint256 repaymentChainId,\n uint256 updatedOutputAmount,\n address updatedRecipient,\n bytes calldata updatedMessage,\n bytes calldata depositorSignature\n ) external;\n\n function requestV3SlowFill(V3RelayData calldata relayData) external;\n\n function executeV3SlowRelayLeaf(\n V3SlowFill calldata slowFillLeaf,\n uint32 rootBundleId,\n bytes32[] calldata proof\n ) external;\n\n /**************************************\n * ERRORS *\n **************************************/\n\n error DisabledRoute();\n error InvalidQuoteTimestamp();\n error InvalidFillDeadline();\n error InvalidExclusiveRelayer();\n error InvalidExclusivityDeadline();\n error MsgValueDoesNotMatchInputAmount();\n error NotExclusiveRelayer();\n error NoSlowFillsInExclusivityWindow();\n error RelayFilled();\n error InvalidSlowFillRequest();\n error ExpiredFillDeadline();\n error InvalidMerkleProof();\n error InvalidChainId();\n error InvalidMerkleLeaf();\n error ClaimedMerkleLeaf();\n error InvalidPayoutAdjustmentPct();\n}\n" + }, + "contracts/SpokePoolVerifier.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/utils/Address.sol\";\nimport \"./interfaces/V3SpokePoolInterface.sol\";\n\n/**\n * @notice SpokePoolVerifier is a contract that verifies that the SpokePool exists on this chain before sending ETH to it.\n * @dev This contract must be deployed via Create2 to the same address on all chains. That way, an errant transaction sent\n * to the wrong chain will be blocked by this contract rather than hitting a dead address. This means that this contract\n * will not work to protect chains, like zkSync, where Create2 address derivations don't match other chains.\n * Source: https://era.zksync.io/docs/reference/architecture/differences-with-ethereum.html#create-create2\n * @custom:security-contact bugs@across.to\n */\ncontract SpokePoolVerifier {\n using Address for address;\n\n /**\n * @notice Passthrough function to `depositV3()` on the SpokePool contract.\n * @dev Protects the caller from losing their ETH (or other native token) by reverting if the SpokePool address\n * they intended to call does not exist on this chain. Because this contract can be deployed at the same address\n * everywhere callers should be protected even if the transaction is submitted to an unintended network.\n * This contract should only be used for native token deposits, as this problem only exists for native tokens.\n * @param spokePool Address of the SpokePool contract that the user is intending to call.\n * @param recipient Address to receive funds at on destination chain.\n * @param inputToken Token to lock into this contract to initiate deposit.\n * @param inputAmount Amount of tokens to deposit.\n * @param outputAmount Amount of tokens to receive on destination chain.\n * @param destinationChainId Denotes network where user will receive funds from SpokePool by a relayer.\n * @param quoteTimestamp Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid\n * to LP pool on HubPool.\n * @param message Arbitrary data that can be used to pass additional information to the recipient along with the tokens.\n * Note: this is intended to be used to pass along instructions for how a contract should use or allocate the tokens.\n * @param exclusiveRelayer Address of the relayer who has exclusive rights to fill this deposit. Can be set to\n * 0x0 if no exclusivity period is desired. If so, then must set exclusivityDeadline to 0.\n * @param exclusivityDeadline Timestamp after which any relayer can fill this deposit. Must set\n * to 0 if exclusiveRelayer is set to 0x0, and vice versa.\n * @param fillDeadline Timestamp after which this deposit can no longer be filled.\n */\n function deposit(\n V3SpokePoolInterface spokePool,\n address recipient,\n address inputToken,\n uint256 inputAmount,\n uint256 outputAmount,\n uint256 destinationChainId,\n uint32 quoteTimestamp,\n bytes memory message,\n address exclusiveRelayer,\n uint32 exclusivityDeadline,\n uint32 fillDeadline\n ) external payable {\n require(msg.value == inputAmount, \"msg.value != amount\");\n require(address(spokePool).isContract(), \"spokePool is not a contract\");\n // Set msg.sender as the depositor so that msg.sender can speed up the deposit.\n spokePool.depositV3{ value: msg.value }(\n msg.sender,\n recipient,\n inputToken,\n // @dev Setting outputToken to 0x0 to instruct fillers to use the equivalent token\n // as the originToken on the destination chain.\n address(0),\n inputAmount,\n outputAmount,\n destinationChainId,\n exclusiveRelayer,\n quoteTimestamp,\n fillDeadline,\n exclusivityDeadline,\n message\n );\n }\n}\n" + } + }, + "settings": { + "optimizer": { + "enabled": true, + "runs": 1000000 + }, + "viaIR": true, + "debug": { + "revertStrings": "strip" + }, + "outputSelection": { + "*": { + "*": [ + "abi", + "evm.bytecode", + "evm.deployedBytecode", + "evm.methodIdentifiers", + "metadata", + "devdoc", + "userdoc", + "storageLayout", + "evm.gasEstimates" + ], + "": ["ast"] + } + }, + "metadata": { + "useLiteralContent": true + } + } +} diff --git a/deployments/linea/solcInputs/783274f805324492b21545b62eb0dbfe.json b/deployments/linea/solcInputs/783274f805324492b21545b62eb0dbfe.json new file mode 100644 index 000000000..4bcffc07b --- /dev/null +++ b/deployments/linea/solcInputs/783274f805324492b21545b62eb0dbfe.json @@ -0,0 +1,43 @@ +{ + "language": "Solidity", + "sources": { + "@openzeppelin/contracts/utils/Address.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (utils/Address.sol)\n\npragma solidity ^0.8.1;\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 * Furthermore, `isContract` will also return true if the target contract within\n * the same transaction is already scheduled for destruction by `SELFDESTRUCT`,\n * which only has an effect at the end of a transaction.\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 > 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://consensys.net/diligence/blog/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.8.0/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n require(address(this).balance >= amount, \"Address: insufficient balance\");\n\n (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 functionCallWithValue(target, data, 0, \"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(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n return functionCallWithValue(target, data, value, \"Address: low-level call with value failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\n * with `errorMessage` as a fallback revert reason when `target` reverts.\n *\n * _Available since v3.1._\n */\n function functionCallWithValue(\n address target,\n bytes memory data,\n uint256 value,\n string memory errorMessage\n ) internal returns (bytes memory) {\n require(address(this).balance >= value, \"Address: insufficient balance for call\");\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, 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 (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, 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 (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata, errorMessage);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling\n * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.\n *\n * _Available since v4.8._\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata,\n string memory errorMessage\n ) internal view returns (bytes memory) {\n if (success) {\n if (returndata.length == 0) {\n // only check isContract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n require(isContract(target), \"Address: call to non-contract\");\n }\n return returndata;\n } else {\n _revert(returndata, errorMessage);\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the\n * revert reason or 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 _revert(returndata, errorMessage);\n }\n }\n\n function _revert(bytes memory returndata, string memory errorMessage) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length > 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert(errorMessage);\n }\n }\n}\n" + }, + "contracts/interfaces/V3SpokePoolInterface.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n// Contains structs and functions used by SpokePool contracts to facilitate universal settlement.\ninterface V3SpokePoolInterface {\n /**************************************\n * ENUMS *\n **************************************/\n\n // Fill status tracks on-chain state of deposit, uniquely identified by relayHash.\n enum FillStatus {\n Unfilled,\n RequestedSlowFill,\n Filled\n }\n // Fill type is emitted in the FilledRelay event to assist Dataworker with determining which types of\n // fills to refund (e.g. only fast fills) and whether a fast fill created a sow fill excess.\n enum FillType {\n FastFill,\n // Fast fills are normal fills that do not replace a slow fill request.\n ReplacedSlowFill,\n // Replaced slow fills are fast fills that replace a slow fill request. This type is used by the Dataworker\n // to know when to send excess funds from the SpokePool to the HubPool because they can no longer be used\n // for a slow fill execution.\n SlowFill\n // Slow fills are requested via requestSlowFill and executed by executeSlowRelayLeaf after a bundle containing\n // the slow fill is validated.\n }\n\n /**************************************\n * STRUCTS *\n **************************************/\n\n // This struct represents the data to fully specify a **unique** relay submitted on this chain.\n // This data is hashed with the chainId() and saved by the SpokePool to prevent collisions and protect against\n // replay attacks on other chains. If any portion of this data differs, the relay is considered to be\n // completely distinct.\n struct V3RelayData {\n // The address that made the deposit on the origin chain.\n address depositor;\n // The recipient address on the destination chain.\n address recipient;\n // This is the exclusive relayer who can fill the deposit before the exclusivity deadline.\n address exclusiveRelayer;\n // Token that is deposited on origin chain by depositor.\n address inputToken;\n // Token that is received on destination chain by recipient.\n address outputToken;\n // The amount of input token deposited by depositor.\n uint256 inputAmount;\n // The amount of output token to be received by recipient.\n uint256 outputAmount;\n // Origin chain id.\n uint256 originChainId;\n // The id uniquely identifying this deposit on the origin chain.\n uint32 depositId;\n // The timestamp on the destination chain after which this deposit can no longer be filled.\n uint32 fillDeadline;\n // The timestamp on the destination chain after which any relayer can fill the deposit.\n uint32 exclusivityDeadline;\n // Data that is forwarded to the recipient.\n bytes message;\n }\n\n // Contains parameters passed in by someone who wants to execute a slow relay leaf.\n struct V3SlowFill {\n V3RelayData relayData;\n uint256 chainId;\n uint256 updatedOutputAmount;\n }\n\n // Contains information about a relay to be sent along with additional information that is not unique to the\n // relay itself but is required to know how to process the relay. For example, \"updatedX\" fields can be used\n // by the relayer to modify fields of the relay with the depositor's permission, and \"repaymentChainId\" is specified\n // by the relayer to determine where to take a relayer refund, but doesn't affect the uniqueness of the relay.\n struct V3RelayExecutionParams {\n V3RelayData relay;\n bytes32 relayHash;\n uint256 updatedOutputAmount;\n address updatedRecipient;\n bytes updatedMessage;\n uint256 repaymentChainId;\n }\n\n // Packs together parameters emitted in FilledV3Relay because there are too many emitted otherwise.\n // Similar to V3RelayExecutionParams, these parameters are not used to uniquely identify the deposit being\n // filled so they don't have to be unpacked by all clients.\n struct V3RelayExecutionEventInfo {\n address updatedRecipient;\n bytes updatedMessage;\n uint256 updatedOutputAmount;\n FillType fillType;\n }\n\n /**************************************\n * EVENTS *\n **************************************/\n\n event V3FundsDeposited(\n address inputToken,\n address outputToken,\n uint256 inputAmount,\n uint256 outputAmount,\n uint256 indexed destinationChainId,\n uint32 indexed depositId,\n uint32 quoteTimestamp,\n uint32 fillDeadline,\n uint32 exclusivityDeadline,\n address indexed depositor,\n address recipient,\n address exclusiveRelayer,\n bytes message\n );\n\n event RequestedSpeedUpV3Deposit(\n uint256 updatedOutputAmount,\n uint32 indexed depositId,\n address indexed depositor,\n address updatedRecipient,\n bytes updatedMessage,\n bytes depositorSignature\n );\n\n event FilledV3Relay(\n address inputToken,\n address outputToken,\n uint256 inputAmount,\n uint256 outputAmount,\n uint256 repaymentChainId,\n uint256 indexed originChainId,\n uint32 indexed depositId,\n uint32 fillDeadline,\n uint32 exclusivityDeadline,\n address exclusiveRelayer,\n address indexed relayer,\n address depositor,\n address recipient,\n bytes message,\n V3RelayExecutionEventInfo relayExecutionInfo\n );\n\n event RequestedV3SlowFill(\n address inputToken,\n address outputToken,\n uint256 inputAmount,\n uint256 outputAmount,\n uint256 indexed originChainId,\n uint32 indexed depositId,\n uint32 fillDeadline,\n uint32 exclusivityDeadline,\n address exclusiveRelayer,\n address depositor,\n address recipient,\n bytes message\n );\n\n /**************************************\n * FUNCTIONS *\n **************************************/\n\n function depositV3(\n address depositor,\n address recipient,\n address inputToken,\n address outputToken,\n uint256 inputAmount,\n uint256 outputAmount,\n uint256 destinationChainId,\n address exclusiveRelayer,\n uint32 quoteTimestamp,\n uint32 fillDeadline,\n uint32 exclusivityDeadline,\n bytes calldata message\n ) external payable;\n\n function depositV3Now(\n address depositor,\n address recipient,\n address inputToken,\n address outputToken,\n uint256 inputAmount,\n uint256 outputAmount,\n uint256 destinationChainId,\n address exclusiveRelayer,\n uint32 fillDeadlineOffset,\n uint32 exclusivityDeadline,\n bytes calldata message\n ) external payable;\n\n function speedUpV3Deposit(\n address depositor,\n uint32 depositId,\n uint256 updatedOutputAmount,\n address updatedRecipient,\n bytes calldata updatedMessage,\n bytes calldata depositorSignature\n ) external;\n\n function fillV3Relay(V3RelayData calldata relayData, uint256 repaymentChainId) external;\n\n function fillV3RelayWithUpdatedDeposit(\n V3RelayData calldata relayData,\n uint256 repaymentChainId,\n uint256 updatedOutputAmount,\n address updatedRecipient,\n bytes calldata updatedMessage,\n bytes calldata depositorSignature\n ) external;\n\n function requestV3SlowFill(V3RelayData calldata relayData) external;\n\n function executeV3SlowRelayLeaf(\n V3SlowFill calldata slowFillLeaf,\n uint32 rootBundleId,\n bytes32[] calldata proof\n ) external;\n\n /**************************************\n * ERRORS *\n **************************************/\n\n error DisabledRoute();\n error InvalidQuoteTimestamp();\n error InvalidFillDeadline();\n error InvalidExclusiveRelayer();\n error InvalidExclusivityDeadline();\n error MsgValueDoesNotMatchInputAmount();\n error NotExclusiveRelayer();\n error NoSlowFillsInExclusivityWindow();\n error RelayFilled();\n error InvalidSlowFillRequest();\n error ExpiredFillDeadline();\n error InvalidMerkleProof();\n error InvalidChainId();\n error InvalidMerkleLeaf();\n error ClaimedMerkleLeaf();\n error InvalidPayoutAdjustmentPct();\n}\n" + }, + "contracts/SpokePoolVerifier.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/utils/Address.sol\";\nimport \"./interfaces/V3SpokePoolInterface.sol\";\n\n/**\n * @notice SpokePoolVerifier is a contract that verifies that the SpokePool exists on this chain before sending ETH to it.\n * @dev This contract must be deployed via Create2 to the same address on all chains. That way, an errant transaction sent\n * to the wrong chain will be blocked by this contract rather than hitting a dead address. This means that this contract\n * will not work to protect chains, like zkSync, where Create2 address derivations don't match other chains.\n * Source: https://era.zksync.io/docs/reference/architecture/differences-with-ethereum.html#create-create2\n * @custom:security-contact bugs@across.to\n */\ncontract SpokePoolVerifier {\n using Address for address;\n\n /**\n * @notice Passthrough function to `depositV3()` on the SpokePool contract.\n * @dev Protects the caller from losing their ETH (or other native token) by reverting if the SpokePool address\n * they intended to call does not exist on this chain. Because this contract can be deployed at the same address\n * everywhere callers should be protected even if the transaction is submitted to an unintended network.\n * This contract should only be used for native token deposits, as this problem only exists for native tokens.\n * @param spokePool Address of the SpokePool contract that the user is intending to call.\n * @param recipient Address to receive funds at on destination chain.\n * @param inputToken Token to lock into this contract to initiate deposit.\n * @param inputAmount Amount of tokens to deposit.\n * @param outputAmount Amount of tokens to receive on destination chain.\n * @param destinationChainId Denotes network where user will receive funds from SpokePool by a relayer.\n * @param quoteTimestamp Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid\n * to LP pool on HubPool.\n * @param message Arbitrary data that can be used to pass additional information to the recipient along with the tokens.\n * Note: this is intended to be used to pass along instructions for how a contract should use or allocate the tokens.\n * @param exclusiveRelayer Address of the relayer who has exclusive rights to fill this deposit. Can be set to\n * 0x0 if no exclusivity period is desired. If so, then must set exclusivityDeadline to 0.\n * @param exclusivityDeadline Timestamp after which any relayer can fill this deposit. Must set\n * to 0 if exclusiveRelayer is set to 0x0, and vice versa.\n * @param fillDeadline Timestamp after which this deposit can no longer be filled.\n */\n function deposit(\n V3SpokePoolInterface spokePool,\n address recipient,\n address inputToken,\n uint256 inputAmount,\n uint256 outputAmount,\n uint256 destinationChainId,\n address exclusiveRelayer,\n uint32 quoteTimestamp,\n uint32 fillDeadline,\n uint32 exclusivityDeadline,\n bytes memory message\n ) external payable {\n require(msg.value == inputAmount, \"msg.value != amount\");\n require(address(spokePool).isContract(), \"spokePool is not a contract\");\n // Set msg.sender as the depositor so that msg.sender can speed up the deposit.\n spokePool.depositV3{ value: msg.value }(\n msg.sender,\n recipient,\n inputToken,\n // @dev Setting outputToken to 0x0 to instruct fillers to use the equivalent token\n // as the originToken on the destination chain.\n address(0),\n inputAmount,\n outputAmount,\n destinationChainId,\n exclusiveRelayer,\n quoteTimestamp,\n fillDeadline,\n exclusivityDeadline,\n message\n );\n }\n}\n" + } + }, + "settings": { + "optimizer": { + "enabled": true, + "runs": 1000000 + }, + "viaIR": true, + "debug": { + "revertStrings": "strip" + }, + "outputSelection": { + "*": { + "*": [ + "abi", + "evm.bytecode", + "evm.deployedBytecode", + "evm.methodIdentifiers", + "metadata", + "devdoc", + "userdoc", + "storageLayout", + "evm.gasEstimates" + ], + "": ["ast"] + } + }, + "metadata": { + "useLiteralContent": true + } + } +} diff --git a/deployments/lisk/SpokePoolVerifier.json b/deployments/lisk/SpokePoolVerifier.json index 95cc0087d..4e0d74c1f 100644 --- a/deployments/lisk/SpokePoolVerifier.json +++ b/deployments/lisk/SpokePoolVerifier.json @@ -1,10 +1,10 @@ { - "address": "0xB4A8d45647445EA9FC3E1058096142390683dBC2", + "address": "0x4437A1Ee2dFb72954F21A44C3F0F0E2CBA5A5C27", "abi": [ { "inputs": [ { - "internalType": "contract SpokePoolInterface", + "internalType": "contract V3SpokePoolInterface", "name": "spokePool", "type": "address" }, @@ -15,12 +15,17 @@ }, { "internalType": "address", - "name": "originToken", + "name": "inputToken", "type": "address" }, { "internalType": "uint256", - "name": "amount", + "name": "inputAmount", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "outputAmount", "type": "uint256" }, { @@ -29,24 +34,29 @@ "type": "uint256" }, { - "internalType": "int64", - "name": "relayerFeePct", - "type": "int64" + "internalType": "address", + "name": "exclusiveRelayer", + "type": "address" }, { "internalType": "uint32", "name": "quoteTimestamp", "type": "uint32" }, + { + "internalType": "uint32", + "name": "fillDeadline", + "type": "uint32" + }, + { + "internalType": "uint32", + "name": "exclusivityDeadline", + "type": "uint32" + }, { "internalType": "bytes", "name": "message", "type": "bytes" - }, - { - "internalType": "uint256", - "name": "maxCount", - "type": "uint256" } ], "name": "deposit", @@ -55,43 +65,46 @@ "type": "function" } ], - "transactionHash": "0xd499b47192c53981bb060fa178c35284183c2c312f69a31f25fbd6a19e9d0f44", + "transactionHash": "0xf83243a22fea558fab53188fee7cc5362bd65f20e8417368302fbdcde7cae69b", "receipt": { "to": "0x4e59b44847b379578588920cA78FbF26c0B4956C", "from": "0x9A8f92a830A5cB89a3816e3D267CB7791c16b04D", "contractAddress": null, "transactionIndex": 1, - "gasUsed": "234906", + "gasUsed": "254525", "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - "blockHash": "0x482be94209e92a4a459de19f788765cd75ce3333f53143a7c6045cdeae6e1f24", - "transactionHash": "0xd499b47192c53981bb060fa178c35284183c2c312f69a31f25fbd6a19e9d0f44", + "blockHash": "0x6cf4ed0862e77d287ff30567585644d423419eba4aa04b685fb1b678e53d5797", + "transactionHash": "0xf83243a22fea558fab53188fee7cc5362bd65f20e8417368302fbdcde7cae69b", "logs": [], - "blockNumber": 2391565, - "cumulativeGasUsed": "278757", + "blockNumber": 3643402, + "cumulativeGasUsed": "306752", "status": 1, "byzantium": true }, "args": [], - "numDeployments": 1, - "solcInputHash": "53ab13385da43753d9a657e7780a0560", - "metadata": "{\"compiler\":{\"version\":\"0.8.19+commit.7dd6d404\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"contract SpokePoolInterface\",\"name\":\"spokePool\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"internalType\":\"int64\",\"name\":\"relayerFeePct\",\"type\":\"int64\"},{\"internalType\":\"uint32\",\"name\":\"quoteTimestamp\",\"type\":\"uint32\"},{\"internalType\":\"bytes\",\"name\":\"message\",\"type\":\"bytes\"},{\"internalType\":\"uint256\",\"name\":\"maxCount\",\"type\":\"uint256\"}],\"name\":\"deposit\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"This contract must be deployed via Create2 to the same address on all chains. That way, an errant transaction sent to the wrong chain will be blocked by this contract rather than hitting a dead address. This means that this contract will not work to protect chains, like zkSync, where Create2 address derivations don't match other chains. Source: https://era.zksync.io/docs/reference/architecture/differences-with-ethereum.html#create-create2\",\"kind\":\"dev\",\"methods\":{\"deposit(address,address,address,uint256,uint256,int64,uint32,bytes,uint256)\":{\"details\":\"Protects the caller from losing their ETH (or other native token) by reverting if the SpokePool address they intended to call does not exist on this chain. Because this contract can be deployed at the same address everywhere callers should be protected even if the transaction is submitted to an unintended network. This contract should only be used for native token deposits, as this problem only exists for native tokens.\",\"params\":{\"amount\":\"Amount of tokens to deposit. Will be amount of tokens to receive less fees.\",\"destinationChainId\":\"Denotes network where user will receive funds from SpokePool by a relayer.\",\"maxCount\":\"used to protect the depositor from frontrunning to guarantee their quote remains valid. Note: this is intended to be used to pass along instructions for how a contract should use or allocate the tokens.\",\"message\":\"Arbitrary data that can be used to pass additional information to the recipient along with the tokens. Note: this is intended to be used to pass along instructions for how a contract should use or allocate the tokens.\",\"originToken\":\"Token to lock into this contract to initiate deposit.\",\"quoteTimestamp\":\"Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid to LP pool on HubPool.\",\"recipient\":\"Address to receive funds at on destination chain.\",\"relayerFeePct\":\"% of deposit amount taken out to incentivize a fast relayer.\",\"spokePool\":\"Address of the SpokePool contract that the user is intending to call.\"}}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"deposit(address,address,address,uint256,uint256,int64,uint32,bytes,uint256)\":{\"notice\":\"Passthrough function to `depositV3()` on the SpokePool contract.\"}},\"notice\":\"SpokePoolVerifier is a contract that verifies that the SpokePool exists on this chain before sending ETH to it.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/SpokePoolVerifier.sol\":\"SpokePoolVerifier\"},\"debug\":{\"revertStrings\":\"strip\"},\"evmVersion\":\"paris\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":1000000},\"remappings\":[],\"viaIR\":true},\"sources\":{\"@openzeppelin/contracts/utils/Address.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.9.0) (utils/Address.sol)\\n\\npragma solidity ^0.8.1;\\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 * Furthermore, `isContract` will also return true if the target contract within\\n * the same transaction is already scheduled for destruction by `SELFDESTRUCT`,\\n * which only has an effect at the end of a transaction.\\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 > 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://consensys.net/diligence/blog/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.8.0/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\\n */\\n function sendValue(address payable recipient, uint256 amount) internal {\\n require(address(this).balance >= amount, \\\"Address: insufficient balance\\\");\\n\\n (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 functionCallWithValue(target, data, 0, \\\"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(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, value, \\\"Address: low-level call with value failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\\n * with `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(address(this).balance >= value, \\\"Address: insufficient balance for call\\\");\\n (bool success, bytes memory returndata) = target.call{value: value}(data);\\n return verifyCallResultFromTarget(target, 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 (bool success, bytes memory returndata) = target.staticcall(data);\\n return verifyCallResultFromTarget(target, 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 (bool success, bytes memory returndata) = target.delegatecall(data);\\n return verifyCallResultFromTarget(target, success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling\\n * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.\\n *\\n * _Available since v4.8._\\n */\\n function verifyCallResultFromTarget(\\n address target,\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n if (success) {\\n if (returndata.length == 0) {\\n // only check isContract if the call was successful and the return data is empty\\n // otherwise we already know that it was a contract\\n require(isContract(target), \\\"Address: call to non-contract\\\");\\n }\\n return returndata;\\n } else {\\n _revert(returndata, errorMessage);\\n }\\n }\\n\\n /**\\n * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the\\n * revert reason or 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 _revert(returndata, errorMessage);\\n }\\n }\\n\\n function _revert(bytes memory returndata, string memory errorMessage) private pure {\\n // Look for revert reason and bubble it up if present\\n if (returndata.length > 0) {\\n // The easiest way to bubble the revert reason is using memory via assembly\\n /// @solidity memory-safe-assembly\\n assembly {\\n let returndata_size := mload(returndata)\\n revert(add(32, returndata), returndata_size)\\n }\\n } else {\\n revert(errorMessage);\\n }\\n }\\n}\\n\",\"keccak256\":\"0x006dd67219697fe68d7fbfdea512e7c4cb64a43565ed86171d67e844982da6fa\",\"license\":\"MIT\"},\"contracts/SpokePoolVerifier.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\nimport \\\"@openzeppelin/contracts/utils/Address.sol\\\";\\nimport \\\"./interfaces/SpokePoolInterface.sol\\\";\\n\\n/**\\n * @notice SpokePoolVerifier is a contract that verifies that the SpokePool exists on this chain before sending ETH to it.\\n * @dev This contract must be deployed via Create2 to the same address on all chains. That way, an errant transaction sent\\n * to the wrong chain will be blocked by this contract rather than hitting a dead address. This means that this contract\\n * will not work to protect chains, like zkSync, where Create2 address derivations don't match other chains.\\n * Source: https://era.zksync.io/docs/reference/architecture/differences-with-ethereum.html#create-create2\\n */\\ncontract SpokePoolVerifier {\\n using Address for address;\\n\\n /**\\n * @notice Passthrough function to `depositV3()` on the SpokePool contract.\\n * @dev Protects the caller from losing their ETH (or other native token) by reverting if the SpokePool address\\n * they intended to call does not exist on this chain. Because this contract can be deployed at the same address\\n * everywhere callers should be protected even if the transaction is submitted to an unintended network.\\n * This contract should only be used for native token deposits, as this problem only exists for native tokens.\\n * @param spokePool Address of the SpokePool contract that the user is intending to call.\\n * @param recipient Address to receive funds at on destination chain.\\n * @param originToken Token to lock into this contract to initiate deposit.\\n * @param amount Amount of tokens to deposit. Will be amount of tokens to receive less fees.\\n * @param destinationChainId Denotes network where user will receive funds from SpokePool by a relayer.\\n * @param relayerFeePct % of deposit amount taken out to incentivize a fast relayer.\\n * @param quoteTimestamp Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid\\n * to LP pool on HubPool.\\n * @param message Arbitrary data that can be used to pass additional information to the recipient along with the tokens.\\n * Note: this is intended to be used to pass along instructions for how a contract should use or allocate the tokens.\\n * @param maxCount used to protect the depositor from frontrunning to guarantee their quote remains valid.\\n * Note: this is intended to be used to pass along instructions for how a contract should use or allocate the tokens.\\n */\\n function deposit(\\n SpokePoolInterface spokePool,\\n address recipient,\\n address originToken,\\n uint256 amount,\\n uint256 destinationChainId,\\n int64 relayerFeePct,\\n uint32 quoteTimestamp,\\n bytes memory message,\\n uint256 maxCount\\n ) external payable {\\n require(msg.value == amount, \\\"msg.value != amount\\\");\\n require(address(spokePool).isContract(), \\\"spokePool is not a contract\\\");\\n // Set msg.sender as the depositor so that msg.sender can speed up the deposit.\\n spokePool.depositFor{ value: msg.value }(\\n msg.sender,\\n recipient,\\n originToken,\\n amount,\\n destinationChainId,\\n relayerFeePct,\\n quoteTimestamp,\\n message,\\n maxCount\\n );\\n }\\n}\\n\",\"keccak256\":\"0xfc008c31a2fde7eb0daedaa823b76931225f41ac882b6d1c515d8a38ccda60ec\",\"license\":\"BUSL-1.1\"},\"contracts/interfaces/SpokePoolInterface.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\n/**\\n * @notice Contains common data structures and functions used by all SpokePool implementations.\\n */\\ninterface SpokePoolInterface {\\n // This leaf is meant to be decoded in the SpokePool to pay out successful relayers.\\n struct RelayerRefundLeaf {\\n // This is the amount to return to the HubPool. This occurs when there is a PoolRebalanceLeaf netSendAmount that\\n // is negative. This is just the negative of this value.\\n uint256 amountToReturn;\\n // Used to verify that this is being executed on the correct destination chainId.\\n uint256 chainId;\\n // This array designates how much each of those addresses should be refunded.\\n uint256[] refundAmounts;\\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\\n uint32 leafId;\\n // The associated L2TokenAddress that these claims apply to.\\n address l2TokenAddress;\\n // Must be same length as refundAmounts and designates each address that must be refunded.\\n address[] refundAddresses;\\n }\\n\\n // Stores collection of merkle roots that can be published to this contract from the HubPool, which are referenced\\n // by \\\"data workers\\\" via inclusion proofs to execute leaves in the roots.\\n struct RootBundle {\\n // Merkle root of slow relays that were not fully filled and whose recipient is still owed funds from the LP pool.\\n bytes32 slowRelayRoot;\\n // Merkle root of relayer refunds for successful relays.\\n bytes32 relayerRefundRoot;\\n // This is a 2D bitmap tracking which leaves in the relayer refund root have been claimed, with max size of\\n // 256x(2^248) leaves per root.\\n mapping(uint256 => uint256) claimedBitmap;\\n }\\n\\n function setCrossDomainAdmin(address newCrossDomainAdmin) external;\\n\\n function setHubPool(address newHubPool) external;\\n\\n function setEnableRoute(\\n address originToken,\\n uint256 destinationChainId,\\n bool enable\\n ) external;\\n\\n function pauseDeposits(bool pause) external;\\n\\n function pauseFills(bool pause) external;\\n\\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) external;\\n\\n function emergencyDeleteRootBundle(uint256 rootBundleId) external;\\n\\n function deposit(\\n address recipient,\\n address originToken,\\n uint256 amount,\\n uint256 destinationChainId,\\n int64 relayerFeePct,\\n uint32 quoteTimestamp,\\n bytes memory message,\\n uint256 maxCount\\n ) external payable;\\n\\n function depositFor(\\n address depositor,\\n address recipient,\\n address originToken,\\n uint256 amount,\\n uint256 destinationChainId,\\n int64 relayerFeePct,\\n uint32 quoteTimestamp,\\n bytes memory message,\\n uint256 maxCount\\n ) external payable;\\n\\n function executeRelayerRefundLeaf(\\n uint32 rootBundleId,\\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\\n bytes32[] memory proof\\n ) external payable;\\n\\n function chainId() external view returns (uint256);\\n\\n error NotEOA();\\n error InvalidDepositorSignature();\\n error InvalidRelayerFeePct();\\n error MaxTransferSizeExceeded();\\n error InvalidCrossDomainAdmin();\\n error InvalidHubPool();\\n error DepositsArePaused();\\n error FillsArePaused();\\n}\\n\",\"keccak256\":\"0xc90fbd7e66e2e87e9aacbe93c20cc020cd1fc582c4fd4879807e7dc026943ea0\",\"license\":\"BUSL-1.1\"}},\"version\":1}", - "bytecode": "0x608080604052346100165761034b908161001c8239f35b600080fdfe600436101561000d57600080fd5b6000803560e01c63e0db3fcf1461002357600080fd5b610120807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103115773ffffffffffffffffffffffffffffffffffffffff600435818116810361030d576024359282841684036103095760443583811681036103055760a4358060070b81036103015760c4359063ffffffff8216820361029b5760e43567ffffffffffffffff81116102fd57366023820112156102fd57806004013567ffffffffffffffff81116102d0577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0603f81601f84011601166080016080811067ffffffffffffffff8211176102a357908a929160405280608052366024828401011161029f57602091819060240160a0376080010152606435340361029b578585163b1561029b578585163b1561029b57859694929163ffffffff91878a9896946040519a8b997f541f4f14000000000000000000000000000000000000000000000000000000008b523360048c01521660248a01521660448801526064356064880152608435608488015260070b60a48701521660c485015260e484015260805180610124850152845b8181106102805750908391827fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f6101449389858286010152610104803590850152011681010301923491165af1801561027557610233575080f35b67ffffffffffffffff81116102485760405280f35b6024827f4e487b710000000000000000000000000000000000000000000000000000000081526041600452fd5b6040513d84823e3d90fd5b60a081015187820161014401528795508694506020016101d6565b8780fd5b8280fd5b60248b7f4e487b710000000000000000000000000000000000000000000000000000000081526041600452fd5b60248a7f4e487b710000000000000000000000000000000000000000000000000000000081526041600452fd5b8880fd5b8680fd5b8580fd5b8480fd5b8380fd5b5080fdfea26469706673582212204f81f550f00970671d0755020f959a6599fd76306000e67b424172e1089b949a64736f6c63430008130033", - "deployedBytecode": "0x600436101561000d57600080fd5b6000803560e01c63e0db3fcf1461002357600080fd5b610120807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103115773ffffffffffffffffffffffffffffffffffffffff600435818116810361030d576024359282841684036103095760443583811681036103055760a4358060070b81036103015760c4359063ffffffff8216820361029b5760e43567ffffffffffffffff81116102fd57366023820112156102fd57806004013567ffffffffffffffff81116102d0577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0603f81601f84011601166080016080811067ffffffffffffffff8211176102a357908a929160405280608052366024828401011161029f57602091819060240160a0376080010152606435340361029b578585163b1561029b578585163b1561029b57859694929163ffffffff91878a9896946040519a8b997f541f4f14000000000000000000000000000000000000000000000000000000008b523360048c01521660248a01521660448801526064356064880152608435608488015260070b60a48701521660c485015260e484015260805180610124850152845b8181106102805750908391827fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f6101449389858286010152610104803590850152011681010301923491165af1801561027557610233575080f35b67ffffffffffffffff81116102485760405280f35b6024827f4e487b710000000000000000000000000000000000000000000000000000000081526041600452fd5b6040513d84823e3d90fd5b60a081015187820161014401528795508694506020016101d6565b8780fd5b8280fd5b60248b7f4e487b710000000000000000000000000000000000000000000000000000000081526041600452fd5b60248a7f4e487b710000000000000000000000000000000000000000000000000000000081526041600452fd5b8880fd5b8680fd5b8580fd5b8480fd5b8380fd5b5080fdfea26469706673582212204f81f550f00970671d0755020f959a6599fd76306000e67b424172e1089b949a64736f6c63430008130033", + "numDeployments": 3, + "solcInputHash": "783274f805324492b21545b62eb0dbfe", + "metadata": "{\"compiler\":{\"version\":\"0.8.19+commit.7dd6d404\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"contract V3SpokePoolInterface\",\"name\":\"spokePool\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"inputToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"inputAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"outputAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"exclusiveRelayer\",\"type\":\"address\"},{\"internalType\":\"uint32\",\"name\":\"quoteTimestamp\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"fillDeadline\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"exclusivityDeadline\",\"type\":\"uint32\"},{\"internalType\":\"bytes\",\"name\":\"message\",\"type\":\"bytes\"}],\"name\":\"deposit\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"}],\"devdoc\":{\"custom:security-contact\":\"bugs@across.to\",\"details\":\"This contract must be deployed via Create2 to the same address on all chains. That way, an errant transaction sent to the wrong chain will be blocked by this contract rather than hitting a dead address. This means that this contract will not work to protect chains, like zkSync, where Create2 address derivations don't match other chains. Source: https://era.zksync.io/docs/reference/architecture/differences-with-ethereum.html#create-create2\",\"kind\":\"dev\",\"methods\":{\"deposit(address,address,address,uint256,uint256,uint256,address,uint32,uint32,uint32,bytes)\":{\"details\":\"Protects the caller from losing their ETH (or other native token) by reverting if the SpokePool address they intended to call does not exist on this chain. Because this contract can be deployed at the same address everywhere callers should be protected even if the transaction is submitted to an unintended network. This contract should only be used for native token deposits, as this problem only exists for native tokens.\",\"params\":{\"destinationChainId\":\"Denotes network where user will receive funds from SpokePool by a relayer.\",\"exclusiveRelayer\":\"Address of the relayer who has exclusive rights to fill this deposit. Can be set to 0x0 if no exclusivity period is desired. If so, then must set exclusivityDeadline to 0.\",\"exclusivityDeadline\":\"Timestamp after which any relayer can fill this deposit. Must set to 0 if exclusiveRelayer is set to 0x0, and vice versa.\",\"fillDeadline\":\"Timestamp after which this deposit can no longer be filled.\",\"inputAmount\":\"Amount of tokens to deposit.\",\"inputToken\":\"Token to lock into this contract to initiate deposit.\",\"message\":\"Arbitrary data that can be used to pass additional information to the recipient along with the tokens. Note: this is intended to be used to pass along instructions for how a contract should use or allocate the tokens.\",\"outputAmount\":\"Amount of tokens to receive on destination chain.\",\"quoteTimestamp\":\"Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid to LP pool on HubPool.\",\"recipient\":\"Address to receive funds at on destination chain.\",\"spokePool\":\"Address of the SpokePool contract that the user is intending to call.\"}}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"deposit(address,address,address,uint256,uint256,uint256,address,uint32,uint32,uint32,bytes)\":{\"notice\":\"Passthrough function to `depositV3()` on the SpokePool contract.\"}},\"notice\":\"SpokePoolVerifier is a contract that verifies that the SpokePool exists on this chain before sending ETH to it.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/SpokePoolVerifier.sol\":\"SpokePoolVerifier\"},\"debug\":{\"revertStrings\":\"strip\"},\"evmVersion\":\"paris\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":1000000},\"remappings\":[],\"viaIR\":true},\"sources\":{\"@openzeppelin/contracts/utils/Address.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.9.0) (utils/Address.sol)\\n\\npragma solidity ^0.8.1;\\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 * Furthermore, `isContract` will also return true if the target contract within\\n * the same transaction is already scheduled for destruction by `SELFDESTRUCT`,\\n * which only has an effect at the end of a transaction.\\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 > 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://consensys.net/diligence/blog/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.8.0/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\\n */\\n function sendValue(address payable recipient, uint256 amount) internal {\\n require(address(this).balance >= amount, \\\"Address: insufficient balance\\\");\\n\\n (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 functionCallWithValue(target, data, 0, \\\"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(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, value, \\\"Address: low-level call with value failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\\n * with `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(address(this).balance >= value, \\\"Address: insufficient balance for call\\\");\\n (bool success, bytes memory returndata) = target.call{value: value}(data);\\n return verifyCallResultFromTarget(target, 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 (bool success, bytes memory returndata) = target.staticcall(data);\\n return verifyCallResultFromTarget(target, 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 (bool success, bytes memory returndata) = target.delegatecall(data);\\n return verifyCallResultFromTarget(target, success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling\\n * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.\\n *\\n * _Available since v4.8._\\n */\\n function verifyCallResultFromTarget(\\n address target,\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n if (success) {\\n if (returndata.length == 0) {\\n // only check isContract if the call was successful and the return data is empty\\n // otherwise we already know that it was a contract\\n require(isContract(target), \\\"Address: call to non-contract\\\");\\n }\\n return returndata;\\n } else {\\n _revert(returndata, errorMessage);\\n }\\n }\\n\\n /**\\n * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the\\n * revert reason or 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 _revert(returndata, errorMessage);\\n }\\n }\\n\\n function _revert(bytes memory returndata, string memory errorMessage) private pure {\\n // Look for revert reason and bubble it up if present\\n if (returndata.length > 0) {\\n // The easiest way to bubble the revert reason is using memory via assembly\\n /// @solidity memory-safe-assembly\\n assembly {\\n let returndata_size := mload(returndata)\\n revert(add(32, returndata), returndata_size)\\n }\\n } else {\\n revert(errorMessage);\\n }\\n }\\n}\\n\",\"keccak256\":\"0x006dd67219697fe68d7fbfdea512e7c4cb64a43565ed86171d67e844982da6fa\",\"license\":\"MIT\"},\"contracts/SpokePoolVerifier.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\nimport \\\"@openzeppelin/contracts/utils/Address.sol\\\";\\nimport \\\"./interfaces/V3SpokePoolInterface.sol\\\";\\n\\n/**\\n * @notice SpokePoolVerifier is a contract that verifies that the SpokePool exists on this chain before sending ETH to it.\\n * @dev This contract must be deployed via Create2 to the same address on all chains. That way, an errant transaction sent\\n * to the wrong chain will be blocked by this contract rather than hitting a dead address. This means that this contract\\n * will not work to protect chains, like zkSync, where Create2 address derivations don't match other chains.\\n * Source: https://era.zksync.io/docs/reference/architecture/differences-with-ethereum.html#create-create2\\n * @custom:security-contact bugs@across.to\\n */\\ncontract SpokePoolVerifier {\\n using Address for address;\\n\\n /**\\n * @notice Passthrough function to `depositV3()` on the SpokePool contract.\\n * @dev Protects the caller from losing their ETH (or other native token) by reverting if the SpokePool address\\n * they intended to call does not exist on this chain. Because this contract can be deployed at the same address\\n * everywhere callers should be protected even if the transaction is submitted to an unintended network.\\n * This contract should only be used for native token deposits, as this problem only exists for native tokens.\\n * @param spokePool Address of the SpokePool contract that the user is intending to call.\\n * @param recipient Address to receive funds at on destination chain.\\n * @param inputToken Token to lock into this contract to initiate deposit.\\n * @param inputAmount Amount of tokens to deposit.\\n * @param outputAmount Amount of tokens to receive on destination chain.\\n * @param destinationChainId Denotes network where user will receive funds from SpokePool by a relayer.\\n * @param quoteTimestamp Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid\\n * to LP pool on HubPool.\\n * @param message Arbitrary data that can be used to pass additional information to the recipient along with the tokens.\\n * Note: this is intended to be used to pass along instructions for how a contract should use or allocate the tokens.\\n * @param exclusiveRelayer Address of the relayer who has exclusive rights to fill this deposit. Can be set to\\n * 0x0 if no exclusivity period is desired. If so, then must set exclusivityDeadline to 0.\\n * @param exclusivityDeadline Timestamp after which any relayer can fill this deposit. Must set\\n * to 0 if exclusiveRelayer is set to 0x0, and vice versa.\\n * @param fillDeadline Timestamp after which this deposit can no longer be filled.\\n */\\n function deposit(\\n V3SpokePoolInterface spokePool,\\n address recipient,\\n address inputToken,\\n uint256 inputAmount,\\n uint256 outputAmount,\\n uint256 destinationChainId,\\n address exclusiveRelayer,\\n uint32 quoteTimestamp,\\n uint32 fillDeadline,\\n uint32 exclusivityDeadline,\\n bytes memory message\\n ) external payable {\\n require(msg.value == inputAmount, \\\"msg.value != amount\\\");\\n require(address(spokePool).isContract(), \\\"spokePool is not a contract\\\");\\n // Set msg.sender as the depositor so that msg.sender can speed up the deposit.\\n spokePool.depositV3{ value: msg.value }(\\n msg.sender,\\n recipient,\\n inputToken,\\n // @dev Setting outputToken to 0x0 to instruct fillers to use the equivalent token\\n // as the originToken on the destination chain.\\n address(0),\\n inputAmount,\\n outputAmount,\\n destinationChainId,\\n exclusiveRelayer,\\n quoteTimestamp,\\n fillDeadline,\\n exclusivityDeadline,\\n message\\n );\\n }\\n}\\n\",\"keccak256\":\"0xd5b1ec1b7048634a8b0a7e1e2c68ce51e410157b14778a207b64aff49bc5c6f0\",\"license\":\"BUSL-1.1\"},\"contracts/interfaces/V3SpokePoolInterface.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\n// Contains structs and functions used by SpokePool contracts to facilitate universal settlement.\\ninterface V3SpokePoolInterface {\\n /**************************************\\n * ENUMS *\\n **************************************/\\n\\n // Fill status tracks on-chain state of deposit, uniquely identified by relayHash.\\n enum FillStatus {\\n Unfilled,\\n RequestedSlowFill,\\n Filled\\n }\\n // Fill type is emitted in the FilledRelay event to assist Dataworker with determining which types of\\n // fills to refund (e.g. only fast fills) and whether a fast fill created a sow fill excess.\\n enum FillType {\\n FastFill,\\n // Fast fills are normal fills that do not replace a slow fill request.\\n ReplacedSlowFill,\\n // Replaced slow fills are fast fills that replace a slow fill request. This type is used by the Dataworker\\n // to know when to send excess funds from the SpokePool to the HubPool because they can no longer be used\\n // for a slow fill execution.\\n SlowFill\\n // Slow fills are requested via requestSlowFill and executed by executeSlowRelayLeaf after a bundle containing\\n // the slow fill is validated.\\n }\\n\\n /**************************************\\n * STRUCTS *\\n **************************************/\\n\\n // This struct represents the data to fully specify a **unique** relay submitted on this chain.\\n // This data is hashed with the chainId() and saved by the SpokePool to prevent collisions and protect against\\n // replay attacks on other chains. If any portion of this data differs, the relay is considered to be\\n // completely distinct.\\n struct V3RelayData {\\n // The address that made the deposit on the origin chain.\\n address depositor;\\n // The recipient address on the destination chain.\\n address recipient;\\n // This is the exclusive relayer who can fill the deposit before the exclusivity deadline.\\n address exclusiveRelayer;\\n // Token that is deposited on origin chain by depositor.\\n address inputToken;\\n // Token that is received on destination chain by recipient.\\n address outputToken;\\n // The amount of input token deposited by depositor.\\n uint256 inputAmount;\\n // The amount of output token to be received by recipient.\\n uint256 outputAmount;\\n // Origin chain id.\\n uint256 originChainId;\\n // The id uniquely identifying this deposit on the origin chain.\\n uint32 depositId;\\n // The timestamp on the destination chain after which this deposit can no longer be filled.\\n uint32 fillDeadline;\\n // The timestamp on the destination chain after which any relayer can fill the deposit.\\n uint32 exclusivityDeadline;\\n // Data that is forwarded to the recipient.\\n bytes message;\\n }\\n\\n // Contains parameters passed in by someone who wants to execute a slow relay leaf.\\n struct V3SlowFill {\\n V3RelayData relayData;\\n uint256 chainId;\\n uint256 updatedOutputAmount;\\n }\\n\\n // Contains information about a relay to be sent along with additional information that is not unique to the\\n // relay itself but is required to know how to process the relay. For example, \\\"updatedX\\\" fields can be used\\n // by the relayer to modify fields of the relay with the depositor's permission, and \\\"repaymentChainId\\\" is specified\\n // by the relayer to determine where to take a relayer refund, but doesn't affect the uniqueness of the relay.\\n struct V3RelayExecutionParams {\\n V3RelayData relay;\\n bytes32 relayHash;\\n uint256 updatedOutputAmount;\\n address updatedRecipient;\\n bytes updatedMessage;\\n uint256 repaymentChainId;\\n }\\n\\n // Packs together parameters emitted in FilledV3Relay because there are too many emitted otherwise.\\n // Similar to V3RelayExecutionParams, these parameters are not used to uniquely identify the deposit being\\n // filled so they don't have to be unpacked by all clients.\\n struct V3RelayExecutionEventInfo {\\n address updatedRecipient;\\n bytes updatedMessage;\\n uint256 updatedOutputAmount;\\n FillType fillType;\\n }\\n\\n /**************************************\\n * EVENTS *\\n **************************************/\\n\\n event V3FundsDeposited(\\n address inputToken,\\n address outputToken,\\n uint256 inputAmount,\\n uint256 outputAmount,\\n uint256 indexed destinationChainId,\\n uint32 indexed depositId,\\n uint32 quoteTimestamp,\\n uint32 fillDeadline,\\n uint32 exclusivityDeadline,\\n address indexed depositor,\\n address recipient,\\n address exclusiveRelayer,\\n bytes message\\n );\\n\\n event RequestedSpeedUpV3Deposit(\\n uint256 updatedOutputAmount,\\n uint32 indexed depositId,\\n address indexed depositor,\\n address updatedRecipient,\\n bytes updatedMessage,\\n bytes depositorSignature\\n );\\n\\n event FilledV3Relay(\\n address inputToken,\\n address outputToken,\\n uint256 inputAmount,\\n uint256 outputAmount,\\n uint256 repaymentChainId,\\n uint256 indexed originChainId,\\n uint32 indexed depositId,\\n uint32 fillDeadline,\\n uint32 exclusivityDeadline,\\n address exclusiveRelayer,\\n address indexed relayer,\\n address depositor,\\n address recipient,\\n bytes message,\\n V3RelayExecutionEventInfo relayExecutionInfo\\n );\\n\\n event RequestedV3SlowFill(\\n address inputToken,\\n address outputToken,\\n uint256 inputAmount,\\n uint256 outputAmount,\\n uint256 indexed originChainId,\\n uint32 indexed depositId,\\n uint32 fillDeadline,\\n uint32 exclusivityDeadline,\\n address exclusiveRelayer,\\n address depositor,\\n address recipient,\\n bytes message\\n );\\n\\n /**************************************\\n * FUNCTIONS *\\n **************************************/\\n\\n function depositV3(\\n address depositor,\\n address recipient,\\n address inputToken,\\n address outputToken,\\n uint256 inputAmount,\\n uint256 outputAmount,\\n uint256 destinationChainId,\\n address exclusiveRelayer,\\n uint32 quoteTimestamp,\\n uint32 fillDeadline,\\n uint32 exclusivityDeadline,\\n bytes calldata message\\n ) external payable;\\n\\n function depositV3Now(\\n address depositor,\\n address recipient,\\n address inputToken,\\n address outputToken,\\n uint256 inputAmount,\\n uint256 outputAmount,\\n uint256 destinationChainId,\\n address exclusiveRelayer,\\n uint32 fillDeadlineOffset,\\n uint32 exclusivityDeadline,\\n bytes calldata message\\n ) external payable;\\n\\n function speedUpV3Deposit(\\n address depositor,\\n uint32 depositId,\\n uint256 updatedOutputAmount,\\n address updatedRecipient,\\n bytes calldata updatedMessage,\\n bytes calldata depositorSignature\\n ) external;\\n\\n function fillV3Relay(V3RelayData calldata relayData, uint256 repaymentChainId) external;\\n\\n function fillV3RelayWithUpdatedDeposit(\\n V3RelayData calldata relayData,\\n uint256 repaymentChainId,\\n uint256 updatedOutputAmount,\\n address updatedRecipient,\\n bytes calldata updatedMessage,\\n bytes calldata depositorSignature\\n ) external;\\n\\n function requestV3SlowFill(V3RelayData calldata relayData) external;\\n\\n function executeV3SlowRelayLeaf(\\n V3SlowFill calldata slowFillLeaf,\\n uint32 rootBundleId,\\n bytes32[] calldata proof\\n ) external;\\n\\n /**************************************\\n * ERRORS *\\n **************************************/\\n\\n error DisabledRoute();\\n error InvalidQuoteTimestamp();\\n error InvalidFillDeadline();\\n error InvalidExclusiveRelayer();\\n error InvalidExclusivityDeadline();\\n error MsgValueDoesNotMatchInputAmount();\\n error NotExclusiveRelayer();\\n error NoSlowFillsInExclusivityWindow();\\n error RelayFilled();\\n error InvalidSlowFillRequest();\\n error ExpiredFillDeadline();\\n error InvalidMerkleProof();\\n error InvalidChainId();\\n error InvalidMerkleLeaf();\\n error ClaimedMerkleLeaf();\\n error InvalidPayoutAdjustmentPct();\\n}\\n\",\"keccak256\":\"0x374b7e9cb8afbcaec69cdbcde480676b5d927db84c7f38221331d1226af68d9d\",\"license\":\"BUSL-1.1\"}},\"version\":1}", + "bytecode": "0x60808060405234610016576103a4908161001c8239f35b600080fdfe600436101561000d57600080fd5b6000803560e01c63902e949c1461002357600080fd5b6101607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261036b5773ffffffffffffffffffffffffffffffffffffffff6004358181168103610367576024359082821682036103635760443591838316830361035f5760c435848116810361035b5760e4359063ffffffff928383168303610357576101043590848216820361035357610124359385851685036103225767ffffffffffffffff610144351161032257366023610144350112156103225767ffffffffffffffff6101443560040135116103265767ffffffffffffffff6004610144350135601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f0116608090810191821191101761032657608060046101443590810135601f81017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f011683016040529182905236910160240111610322576101443560048101359060240160a03760a06004610144350135018a90526064353403610322578887163b15610322578887163b1561032257918589979593888296818e9c60409e9b979e519e8f9d8e917f7b9392320000000000000000000000000000000000000000000000000000000083523360048401521690602401521660448c01528b60648c015260643560848c015260843560a48c015260a43560c48c01521660e48a01521661010488015216610124860152166101448401526101648301610180905260805180610184850152845b8181106103075750908391827fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f6101a49389858286010152011681010301923491165af180156102fc576102ba575080f35b67ffffffffffffffff81116102cf5760405280f35b6024827f4e487b710000000000000000000000000000000000000000000000000000000081526041600452fd5b6040513d84823e3d90fd5b60a08101518782016101a40152879550869450602001610266565b8980fd5b60248a7f4e487b710000000000000000000000000000000000000000000000000000000081526041600452fd5b8880fd5b8780fd5b8580fd5b8480fd5b8380fd5b8280fd5b80fdfea26469706673582212201ceff237e6adbd0d3f92e892f7f3f51306c23eac5f7e3f896c2c723d9e5be3a664736f6c63430008130033", + "deployedBytecode": "0x600436101561000d57600080fd5b6000803560e01c63902e949c1461002357600080fd5b6101607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261036b5773ffffffffffffffffffffffffffffffffffffffff6004358181168103610367576024359082821682036103635760443591838316830361035f5760c435848116810361035b5760e4359063ffffffff928383168303610357576101043590848216820361035357610124359385851685036103225767ffffffffffffffff610144351161032257366023610144350112156103225767ffffffffffffffff6101443560040135116103265767ffffffffffffffff6004610144350135601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f0116608090810191821191101761032657608060046101443590810135601f81017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f011683016040529182905236910160240111610322576101443560048101359060240160a03760a06004610144350135018a90526064353403610322578887163b15610322578887163b1561032257918589979593888296818e9c60409e9b979e519e8f9d8e917f7b9392320000000000000000000000000000000000000000000000000000000083523360048401521690602401521660448c01528b60648c015260643560848c015260843560a48c015260a43560c48c01521660e48a01521661010488015216610124860152166101448401526101648301610180905260805180610184850152845b8181106103075750908391827fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f6101a49389858286010152011681010301923491165af180156102fc576102ba575080f35b67ffffffffffffffff81116102cf5760405280f35b6024827f4e487b710000000000000000000000000000000000000000000000000000000081526041600452fd5b6040513d84823e3d90fd5b60a08101518782016101a40152879550869450602001610266565b8980fd5b60248a7f4e487b710000000000000000000000000000000000000000000000000000000081526041600452fd5b8880fd5b8780fd5b8580fd5b8480fd5b8380fd5b8280fd5b80fdfea26469706673582212201ceff237e6adbd0d3f92e892f7f3f51306c23eac5f7e3f896c2c723d9e5be3a664736f6c63430008130033", "devdoc": { + "custom:security-contact": "bugs@across.to", "details": "This contract must be deployed via Create2 to the same address on all chains. That way, an errant transaction sent to the wrong chain will be blocked by this contract rather than hitting a dead address. This means that this contract will not work to protect chains, like zkSync, where Create2 address derivations don't match other chains. Source: https://era.zksync.io/docs/reference/architecture/differences-with-ethereum.html#create-create2", "kind": "dev", "methods": { - "deposit(address,address,address,uint256,uint256,int64,uint32,bytes,uint256)": { + "deposit(address,address,address,uint256,uint256,uint256,address,uint32,uint32,uint32,bytes)": { "details": "Protects the caller from losing their ETH (or other native token) by reverting if the SpokePool address they intended to call does not exist on this chain. Because this contract can be deployed at the same address everywhere callers should be protected even if the transaction is submitted to an unintended network. This contract should only be used for native token deposits, as this problem only exists for native tokens.", "params": { - "amount": "Amount of tokens to deposit. Will be amount of tokens to receive less fees.", "destinationChainId": "Denotes network where user will receive funds from SpokePool by a relayer.", - "maxCount": "used to protect the depositor from frontrunning to guarantee their quote remains valid. Note: this is intended to be used to pass along instructions for how a contract should use or allocate the tokens.", + "exclusiveRelayer": "Address of the relayer who has exclusive rights to fill this deposit. Can be set to 0x0 if no exclusivity period is desired. If so, then must set exclusivityDeadline to 0.", + "exclusivityDeadline": "Timestamp after which any relayer can fill this deposit. Must set to 0 if exclusiveRelayer is set to 0x0, and vice versa.", + "fillDeadline": "Timestamp after which this deposit can no longer be filled.", + "inputAmount": "Amount of tokens to deposit.", + "inputToken": "Token to lock into this contract to initiate deposit.", "message": "Arbitrary data that can be used to pass additional information to the recipient along with the tokens. Note: this is intended to be used to pass along instructions for how a contract should use or allocate the tokens.", - "originToken": "Token to lock into this contract to initiate deposit.", + "outputAmount": "Amount of tokens to receive on destination chain.", "quoteTimestamp": "Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid to LP pool on HubPool.", "recipient": "Address to receive funds at on destination chain.", - "relayerFeePct": "% of deposit amount taken out to incentivize a fast relayer.", "spokePool": "Address of the SpokePool contract that the user is intending to call." } } @@ -101,7 +114,7 @@ "userdoc": { "kind": "user", "methods": { - "deposit(address,address,address,uint256,uint256,int64,uint32,bytes,uint256)": { + "deposit(address,address,address,uint256,uint256,uint256,address,uint32,uint32,uint32,bytes)": { "notice": "Passthrough function to `depositV3()` on the SpokePool contract." } }, diff --git a/deployments/lisk/solcInputs/1a67233dfe969c05446730f26ab1d2c8.json b/deployments/lisk/solcInputs/1a67233dfe969c05446730f26ab1d2c8.json new file mode 100644 index 000000000..96daeb1aa --- /dev/null +++ b/deployments/lisk/solcInputs/1a67233dfe969c05446730f26ab1d2c8.json @@ -0,0 +1,43 @@ +{ + "language": "Solidity", + "sources": { + "@openzeppelin/contracts/utils/Address.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (utils/Address.sol)\n\npragma solidity ^0.8.1;\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 * Furthermore, `isContract` will also return true if the target contract within\n * the same transaction is already scheduled for destruction by `SELFDESTRUCT`,\n * which only has an effect at the end of a transaction.\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 > 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://consensys.net/diligence/blog/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.8.0/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n require(address(this).balance >= amount, \"Address: insufficient balance\");\n\n (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 functionCallWithValue(target, data, 0, \"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(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n return functionCallWithValue(target, data, value, \"Address: low-level call with value failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\n * with `errorMessage` as a fallback revert reason when `target` reverts.\n *\n * _Available since v3.1._\n */\n function functionCallWithValue(\n address target,\n bytes memory data,\n uint256 value,\n string memory errorMessage\n ) internal returns (bytes memory) {\n require(address(this).balance >= value, \"Address: insufficient balance for call\");\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, 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 (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, 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 (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata, errorMessage);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling\n * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.\n *\n * _Available since v4.8._\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata,\n string memory errorMessage\n ) internal view returns (bytes memory) {\n if (success) {\n if (returndata.length == 0) {\n // only check isContract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n require(isContract(target), \"Address: call to non-contract\");\n }\n return returndata;\n } else {\n _revert(returndata, errorMessage);\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the\n * revert reason or 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 _revert(returndata, errorMessage);\n }\n }\n\n function _revert(bytes memory returndata, string memory errorMessage) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length > 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert(errorMessage);\n }\n }\n}\n" + }, + "contracts/interfaces/V3SpokePoolInterface.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n// Contains structs and functions used by SpokePool contracts to facilitate universal settlement.\ninterface V3SpokePoolInterface {\n /**************************************\n * ENUMS *\n **************************************/\n\n // Fill status tracks on-chain state of deposit, uniquely identified by relayHash.\n enum FillStatus {\n Unfilled,\n RequestedSlowFill,\n Filled\n }\n // Fill type is emitted in the FilledRelay event to assist Dataworker with determining which types of\n // fills to refund (e.g. only fast fills) and whether a fast fill created a sow fill excess.\n enum FillType {\n FastFill,\n // Fast fills are normal fills that do not replace a slow fill request.\n ReplacedSlowFill,\n // Replaced slow fills are fast fills that replace a slow fill request. This type is used by the Dataworker\n // to know when to send excess funds from the SpokePool to the HubPool because they can no longer be used\n // for a slow fill execution.\n SlowFill\n // Slow fills are requested via requestSlowFill and executed by executeSlowRelayLeaf after a bundle containing\n // the slow fill is validated.\n }\n\n /**************************************\n * STRUCTS *\n **************************************/\n\n // This struct represents the data to fully specify a **unique** relay submitted on this chain.\n // This data is hashed with the chainId() and saved by the SpokePool to prevent collisions and protect against\n // replay attacks on other chains. If any portion of this data differs, the relay is considered to be\n // completely distinct.\n struct V3RelayData {\n // The address that made the deposit on the origin chain.\n address depositor;\n // The recipient address on the destination chain.\n address recipient;\n // This is the exclusive relayer who can fill the deposit before the exclusivity deadline.\n address exclusiveRelayer;\n // Token that is deposited on origin chain by depositor.\n address inputToken;\n // Token that is received on destination chain by recipient.\n address outputToken;\n // The amount of input token deposited by depositor.\n uint256 inputAmount;\n // The amount of output token to be received by recipient.\n uint256 outputAmount;\n // Origin chain id.\n uint256 originChainId;\n // The id uniquely identifying this deposit on the origin chain.\n uint32 depositId;\n // The timestamp on the destination chain after which this deposit can no longer be filled.\n uint32 fillDeadline;\n // The timestamp on the destination chain after which any relayer can fill the deposit.\n uint32 exclusivityDeadline;\n // Data that is forwarded to the recipient.\n bytes message;\n }\n\n // Contains parameters passed in by someone who wants to execute a slow relay leaf.\n struct V3SlowFill {\n V3RelayData relayData;\n uint256 chainId;\n uint256 updatedOutputAmount;\n }\n\n // Contains information about a relay to be sent along with additional information that is not unique to the\n // relay itself but is required to know how to process the relay. For example, \"updatedX\" fields can be used\n // by the relayer to modify fields of the relay with the depositor's permission, and \"repaymentChainId\" is specified\n // by the relayer to determine where to take a relayer refund, but doesn't affect the uniqueness of the relay.\n struct V3RelayExecutionParams {\n V3RelayData relay;\n bytes32 relayHash;\n uint256 updatedOutputAmount;\n address updatedRecipient;\n bytes updatedMessage;\n uint256 repaymentChainId;\n }\n\n // Packs together parameters emitted in FilledV3Relay because there are too many emitted otherwise.\n // Similar to V3RelayExecutionParams, these parameters are not used to uniquely identify the deposit being\n // filled so they don't have to be unpacked by all clients.\n struct V3RelayExecutionEventInfo {\n address updatedRecipient;\n bytes updatedMessage;\n uint256 updatedOutputAmount;\n FillType fillType;\n }\n\n /**************************************\n * EVENTS *\n **************************************/\n\n event V3FundsDeposited(\n address inputToken,\n address outputToken,\n uint256 inputAmount,\n uint256 outputAmount,\n uint256 indexed destinationChainId,\n uint32 indexed depositId,\n uint32 quoteTimestamp,\n uint32 fillDeadline,\n uint32 exclusivityDeadline,\n address indexed depositor,\n address recipient,\n address exclusiveRelayer,\n bytes message\n );\n\n event RequestedSpeedUpV3Deposit(\n uint256 updatedOutputAmount,\n uint32 indexed depositId,\n address indexed depositor,\n address updatedRecipient,\n bytes updatedMessage,\n bytes depositorSignature\n );\n\n event FilledV3Relay(\n address inputToken,\n address outputToken,\n uint256 inputAmount,\n uint256 outputAmount,\n uint256 repaymentChainId,\n uint256 indexed originChainId,\n uint32 indexed depositId,\n uint32 fillDeadline,\n uint32 exclusivityDeadline,\n address exclusiveRelayer,\n address indexed relayer,\n address depositor,\n address recipient,\n bytes message,\n V3RelayExecutionEventInfo relayExecutionInfo\n );\n\n event RequestedV3SlowFill(\n address inputToken,\n address outputToken,\n uint256 inputAmount,\n uint256 outputAmount,\n uint256 indexed originChainId,\n uint32 indexed depositId,\n uint32 fillDeadline,\n uint32 exclusivityDeadline,\n address exclusiveRelayer,\n address depositor,\n address recipient,\n bytes message\n );\n\n /**************************************\n * FUNCTIONS *\n **************************************/\n\n function depositV3(\n address depositor,\n address recipient,\n address inputToken,\n address outputToken,\n uint256 inputAmount,\n uint256 outputAmount,\n uint256 destinationChainId,\n address exclusiveRelayer,\n uint32 quoteTimestamp,\n uint32 fillDeadline,\n uint32 exclusivityDeadline,\n bytes calldata message\n ) external payable;\n\n function depositV3Now(\n address depositor,\n address recipient,\n address inputToken,\n address outputToken,\n uint256 inputAmount,\n uint256 outputAmount,\n uint256 destinationChainId,\n address exclusiveRelayer,\n uint32 fillDeadlineOffset,\n uint32 exclusivityDeadline,\n bytes calldata message\n ) external payable;\n\n function speedUpV3Deposit(\n address depositor,\n uint32 depositId,\n uint256 updatedOutputAmount,\n address updatedRecipient,\n bytes calldata updatedMessage,\n bytes calldata depositorSignature\n ) external;\n\n function fillV3Relay(V3RelayData calldata relayData, uint256 repaymentChainId) external;\n\n function fillV3RelayWithUpdatedDeposit(\n V3RelayData calldata relayData,\n uint256 repaymentChainId,\n uint256 updatedOutputAmount,\n address updatedRecipient,\n bytes calldata updatedMessage,\n bytes calldata depositorSignature\n ) external;\n\n function requestV3SlowFill(V3RelayData calldata relayData) external;\n\n function executeV3SlowRelayLeaf(\n V3SlowFill calldata slowFillLeaf,\n uint32 rootBundleId,\n bytes32[] calldata proof\n ) external;\n\n /**************************************\n * ERRORS *\n **************************************/\n\n error DisabledRoute();\n error InvalidQuoteTimestamp();\n error InvalidFillDeadline();\n error InvalidExclusiveRelayer();\n error InvalidExclusivityDeadline();\n error MsgValueDoesNotMatchInputAmount();\n error NotExclusiveRelayer();\n error NoSlowFillsInExclusivityWindow();\n error RelayFilled();\n error InvalidSlowFillRequest();\n error ExpiredFillDeadline();\n error InvalidMerkleProof();\n error InvalidChainId();\n error InvalidMerkleLeaf();\n error ClaimedMerkleLeaf();\n error InvalidPayoutAdjustmentPct();\n}\n" + }, + "contracts/SpokePoolVerifier.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/utils/Address.sol\";\nimport \"./interfaces/V3SpokePoolInterface.sol\";\n\n/**\n * @notice SpokePoolVerifier is a contract that verifies that the SpokePool exists on this chain before sending ETH to it.\n * @dev This contract must be deployed via Create2 to the same address on all chains. That way, an errant transaction sent\n * to the wrong chain will be blocked by this contract rather than hitting a dead address. This means that this contract\n * will not work to protect chains, like zkSync, where Create2 address derivations don't match other chains.\n * Source: https://era.zksync.io/docs/reference/architecture/differences-with-ethereum.html#create-create2\n * @custom:security-contact bugs@across.to\n */\ncontract SpokePoolVerifier {\n using Address for address;\n\n /**\n * @notice Passthrough function to `depositV3()` on the SpokePool contract.\n * @dev Protects the caller from losing their ETH (or other native token) by reverting if the SpokePool address\n * they intended to call does not exist on this chain. Because this contract can be deployed at the same address\n * everywhere callers should be protected even if the transaction is submitted to an unintended network.\n * This contract should only be used for native token deposits, as this problem only exists for native tokens.\n * @param spokePool Address of the SpokePool contract that the user is intending to call.\n * @param recipient Address to receive funds at on destination chain.\n * @param inputToken Token to lock into this contract to initiate deposit.\n * @param inputAmount Amount of tokens to deposit.\n * @param outputAmount Amount of tokens to receive on destination chain.\n * @param destinationChainId Denotes network where user will receive funds from SpokePool by a relayer.\n * @param quoteTimestamp Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid\n * to LP pool on HubPool.\n * @param message Arbitrary data that can be used to pass additional information to the recipient along with the tokens.\n * Note: this is intended to be used to pass along instructions for how a contract should use or allocate the tokens.\n * @param exclusiveRelayer Address of the relayer who has exclusive rights to fill this deposit. Can be set to\n * 0x0 if no exclusivity period is desired. If so, then must set exclusivityDeadline to 0.\n * @param exclusivityDeadline Timestamp after which any relayer can fill this deposit. Must set\n * to 0 if exclusiveRelayer is set to 0x0, and vice versa.\n * @param fillDeadline Timestamp after which this deposit can no longer be filled.\n */\n function deposit(\n V3SpokePoolInterface spokePool,\n address recipient,\n address inputToken,\n uint256 inputAmount,\n uint256 outputAmount,\n uint256 destinationChainId,\n uint32 quoteTimestamp,\n bytes memory message,\n address exclusiveRelayer,\n uint32 exclusivityDeadline,\n uint32 fillDeadline\n ) external payable {\n require(msg.value == inputAmount, \"msg.value != amount\");\n require(address(spokePool).isContract(), \"spokePool is not a contract\");\n // Set msg.sender as the depositor so that msg.sender can speed up the deposit.\n spokePool.depositV3{ value: msg.value }(\n msg.sender,\n recipient,\n inputToken,\n // @dev Setting outputToken to 0x0 to instruct fillers to use the equivalent token\n // as the originToken on the destination chain.\n address(0),\n inputAmount,\n outputAmount,\n destinationChainId,\n exclusiveRelayer,\n quoteTimestamp,\n fillDeadline,\n exclusivityDeadline,\n message\n );\n }\n}\n" + } + }, + "settings": { + "optimizer": { + "enabled": true, + "runs": 1000000 + }, + "viaIR": true, + "debug": { + "revertStrings": "strip" + }, + "outputSelection": { + "*": { + "*": [ + "abi", + "evm.bytecode", + "evm.deployedBytecode", + "evm.methodIdentifiers", + "metadata", + "devdoc", + "userdoc", + "storageLayout", + "evm.gasEstimates" + ], + "": ["ast"] + } + }, + "metadata": { + "useLiteralContent": true + } + } +} diff --git a/deployments/lisk/solcInputs/783274f805324492b21545b62eb0dbfe.json b/deployments/lisk/solcInputs/783274f805324492b21545b62eb0dbfe.json new file mode 100644 index 000000000..4bcffc07b --- /dev/null +++ b/deployments/lisk/solcInputs/783274f805324492b21545b62eb0dbfe.json @@ -0,0 +1,43 @@ +{ + "language": "Solidity", + "sources": { + "@openzeppelin/contracts/utils/Address.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (utils/Address.sol)\n\npragma solidity ^0.8.1;\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 * Furthermore, `isContract` will also return true if the target contract within\n * the same transaction is already scheduled for destruction by `SELFDESTRUCT`,\n * which only has an effect at the end of a transaction.\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 > 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://consensys.net/diligence/blog/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.8.0/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n require(address(this).balance >= amount, \"Address: insufficient balance\");\n\n (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 functionCallWithValue(target, data, 0, \"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(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n return functionCallWithValue(target, data, value, \"Address: low-level call with value failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\n * with `errorMessage` as a fallback revert reason when `target` reverts.\n *\n * _Available since v3.1._\n */\n function functionCallWithValue(\n address target,\n bytes memory data,\n uint256 value,\n string memory errorMessage\n ) internal returns (bytes memory) {\n require(address(this).balance >= value, \"Address: insufficient balance for call\");\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, 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 (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, 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 (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata, errorMessage);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling\n * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.\n *\n * _Available since v4.8._\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata,\n string memory errorMessage\n ) internal view returns (bytes memory) {\n if (success) {\n if (returndata.length == 0) {\n // only check isContract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n require(isContract(target), \"Address: call to non-contract\");\n }\n return returndata;\n } else {\n _revert(returndata, errorMessage);\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the\n * revert reason or 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 _revert(returndata, errorMessage);\n }\n }\n\n function _revert(bytes memory returndata, string memory errorMessage) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length > 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert(errorMessage);\n }\n }\n}\n" + }, + "contracts/interfaces/V3SpokePoolInterface.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n// Contains structs and functions used by SpokePool contracts to facilitate universal settlement.\ninterface V3SpokePoolInterface {\n /**************************************\n * ENUMS *\n **************************************/\n\n // Fill status tracks on-chain state of deposit, uniquely identified by relayHash.\n enum FillStatus {\n Unfilled,\n RequestedSlowFill,\n Filled\n }\n // Fill type is emitted in the FilledRelay event to assist Dataworker with determining which types of\n // fills to refund (e.g. only fast fills) and whether a fast fill created a sow fill excess.\n enum FillType {\n FastFill,\n // Fast fills are normal fills that do not replace a slow fill request.\n ReplacedSlowFill,\n // Replaced slow fills are fast fills that replace a slow fill request. This type is used by the Dataworker\n // to know when to send excess funds from the SpokePool to the HubPool because they can no longer be used\n // for a slow fill execution.\n SlowFill\n // Slow fills are requested via requestSlowFill and executed by executeSlowRelayLeaf after a bundle containing\n // the slow fill is validated.\n }\n\n /**************************************\n * STRUCTS *\n **************************************/\n\n // This struct represents the data to fully specify a **unique** relay submitted on this chain.\n // This data is hashed with the chainId() and saved by the SpokePool to prevent collisions and protect against\n // replay attacks on other chains. If any portion of this data differs, the relay is considered to be\n // completely distinct.\n struct V3RelayData {\n // The address that made the deposit on the origin chain.\n address depositor;\n // The recipient address on the destination chain.\n address recipient;\n // This is the exclusive relayer who can fill the deposit before the exclusivity deadline.\n address exclusiveRelayer;\n // Token that is deposited on origin chain by depositor.\n address inputToken;\n // Token that is received on destination chain by recipient.\n address outputToken;\n // The amount of input token deposited by depositor.\n uint256 inputAmount;\n // The amount of output token to be received by recipient.\n uint256 outputAmount;\n // Origin chain id.\n uint256 originChainId;\n // The id uniquely identifying this deposit on the origin chain.\n uint32 depositId;\n // The timestamp on the destination chain after which this deposit can no longer be filled.\n uint32 fillDeadline;\n // The timestamp on the destination chain after which any relayer can fill the deposit.\n uint32 exclusivityDeadline;\n // Data that is forwarded to the recipient.\n bytes message;\n }\n\n // Contains parameters passed in by someone who wants to execute a slow relay leaf.\n struct V3SlowFill {\n V3RelayData relayData;\n uint256 chainId;\n uint256 updatedOutputAmount;\n }\n\n // Contains information about a relay to be sent along with additional information that is not unique to the\n // relay itself but is required to know how to process the relay. For example, \"updatedX\" fields can be used\n // by the relayer to modify fields of the relay with the depositor's permission, and \"repaymentChainId\" is specified\n // by the relayer to determine where to take a relayer refund, but doesn't affect the uniqueness of the relay.\n struct V3RelayExecutionParams {\n V3RelayData relay;\n bytes32 relayHash;\n uint256 updatedOutputAmount;\n address updatedRecipient;\n bytes updatedMessage;\n uint256 repaymentChainId;\n }\n\n // Packs together parameters emitted in FilledV3Relay because there are too many emitted otherwise.\n // Similar to V3RelayExecutionParams, these parameters are not used to uniquely identify the deposit being\n // filled so they don't have to be unpacked by all clients.\n struct V3RelayExecutionEventInfo {\n address updatedRecipient;\n bytes updatedMessage;\n uint256 updatedOutputAmount;\n FillType fillType;\n }\n\n /**************************************\n * EVENTS *\n **************************************/\n\n event V3FundsDeposited(\n address inputToken,\n address outputToken,\n uint256 inputAmount,\n uint256 outputAmount,\n uint256 indexed destinationChainId,\n uint32 indexed depositId,\n uint32 quoteTimestamp,\n uint32 fillDeadline,\n uint32 exclusivityDeadline,\n address indexed depositor,\n address recipient,\n address exclusiveRelayer,\n bytes message\n );\n\n event RequestedSpeedUpV3Deposit(\n uint256 updatedOutputAmount,\n uint32 indexed depositId,\n address indexed depositor,\n address updatedRecipient,\n bytes updatedMessage,\n bytes depositorSignature\n );\n\n event FilledV3Relay(\n address inputToken,\n address outputToken,\n uint256 inputAmount,\n uint256 outputAmount,\n uint256 repaymentChainId,\n uint256 indexed originChainId,\n uint32 indexed depositId,\n uint32 fillDeadline,\n uint32 exclusivityDeadline,\n address exclusiveRelayer,\n address indexed relayer,\n address depositor,\n address recipient,\n bytes message,\n V3RelayExecutionEventInfo relayExecutionInfo\n );\n\n event RequestedV3SlowFill(\n address inputToken,\n address outputToken,\n uint256 inputAmount,\n uint256 outputAmount,\n uint256 indexed originChainId,\n uint32 indexed depositId,\n uint32 fillDeadline,\n uint32 exclusivityDeadline,\n address exclusiveRelayer,\n address depositor,\n address recipient,\n bytes message\n );\n\n /**************************************\n * FUNCTIONS *\n **************************************/\n\n function depositV3(\n address depositor,\n address recipient,\n address inputToken,\n address outputToken,\n uint256 inputAmount,\n uint256 outputAmount,\n uint256 destinationChainId,\n address exclusiveRelayer,\n uint32 quoteTimestamp,\n uint32 fillDeadline,\n uint32 exclusivityDeadline,\n bytes calldata message\n ) external payable;\n\n function depositV3Now(\n address depositor,\n address recipient,\n address inputToken,\n address outputToken,\n uint256 inputAmount,\n uint256 outputAmount,\n uint256 destinationChainId,\n address exclusiveRelayer,\n uint32 fillDeadlineOffset,\n uint32 exclusivityDeadline,\n bytes calldata message\n ) external payable;\n\n function speedUpV3Deposit(\n address depositor,\n uint32 depositId,\n uint256 updatedOutputAmount,\n address updatedRecipient,\n bytes calldata updatedMessage,\n bytes calldata depositorSignature\n ) external;\n\n function fillV3Relay(V3RelayData calldata relayData, uint256 repaymentChainId) external;\n\n function fillV3RelayWithUpdatedDeposit(\n V3RelayData calldata relayData,\n uint256 repaymentChainId,\n uint256 updatedOutputAmount,\n address updatedRecipient,\n bytes calldata updatedMessage,\n bytes calldata depositorSignature\n ) external;\n\n function requestV3SlowFill(V3RelayData calldata relayData) external;\n\n function executeV3SlowRelayLeaf(\n V3SlowFill calldata slowFillLeaf,\n uint32 rootBundleId,\n bytes32[] calldata proof\n ) external;\n\n /**************************************\n * ERRORS *\n **************************************/\n\n error DisabledRoute();\n error InvalidQuoteTimestamp();\n error InvalidFillDeadline();\n error InvalidExclusiveRelayer();\n error InvalidExclusivityDeadline();\n error MsgValueDoesNotMatchInputAmount();\n error NotExclusiveRelayer();\n error NoSlowFillsInExclusivityWindow();\n error RelayFilled();\n error InvalidSlowFillRequest();\n error ExpiredFillDeadline();\n error InvalidMerkleProof();\n error InvalidChainId();\n error InvalidMerkleLeaf();\n error ClaimedMerkleLeaf();\n error InvalidPayoutAdjustmentPct();\n}\n" + }, + "contracts/SpokePoolVerifier.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/utils/Address.sol\";\nimport \"./interfaces/V3SpokePoolInterface.sol\";\n\n/**\n * @notice SpokePoolVerifier is a contract that verifies that the SpokePool exists on this chain before sending ETH to it.\n * @dev This contract must be deployed via Create2 to the same address on all chains. That way, an errant transaction sent\n * to the wrong chain will be blocked by this contract rather than hitting a dead address. This means that this contract\n * will not work to protect chains, like zkSync, where Create2 address derivations don't match other chains.\n * Source: https://era.zksync.io/docs/reference/architecture/differences-with-ethereum.html#create-create2\n * @custom:security-contact bugs@across.to\n */\ncontract SpokePoolVerifier {\n using Address for address;\n\n /**\n * @notice Passthrough function to `depositV3()` on the SpokePool contract.\n * @dev Protects the caller from losing their ETH (or other native token) by reverting if the SpokePool address\n * they intended to call does not exist on this chain. Because this contract can be deployed at the same address\n * everywhere callers should be protected even if the transaction is submitted to an unintended network.\n * This contract should only be used for native token deposits, as this problem only exists for native tokens.\n * @param spokePool Address of the SpokePool contract that the user is intending to call.\n * @param recipient Address to receive funds at on destination chain.\n * @param inputToken Token to lock into this contract to initiate deposit.\n * @param inputAmount Amount of tokens to deposit.\n * @param outputAmount Amount of tokens to receive on destination chain.\n * @param destinationChainId Denotes network where user will receive funds from SpokePool by a relayer.\n * @param quoteTimestamp Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid\n * to LP pool on HubPool.\n * @param message Arbitrary data that can be used to pass additional information to the recipient along with the tokens.\n * Note: this is intended to be used to pass along instructions for how a contract should use or allocate the tokens.\n * @param exclusiveRelayer Address of the relayer who has exclusive rights to fill this deposit. Can be set to\n * 0x0 if no exclusivity period is desired. If so, then must set exclusivityDeadline to 0.\n * @param exclusivityDeadline Timestamp after which any relayer can fill this deposit. Must set\n * to 0 if exclusiveRelayer is set to 0x0, and vice versa.\n * @param fillDeadline Timestamp after which this deposit can no longer be filled.\n */\n function deposit(\n V3SpokePoolInterface spokePool,\n address recipient,\n address inputToken,\n uint256 inputAmount,\n uint256 outputAmount,\n uint256 destinationChainId,\n address exclusiveRelayer,\n uint32 quoteTimestamp,\n uint32 fillDeadline,\n uint32 exclusivityDeadline,\n bytes memory message\n ) external payable {\n require(msg.value == inputAmount, \"msg.value != amount\");\n require(address(spokePool).isContract(), \"spokePool is not a contract\");\n // Set msg.sender as the depositor so that msg.sender can speed up the deposit.\n spokePool.depositV3{ value: msg.value }(\n msg.sender,\n recipient,\n inputToken,\n // @dev Setting outputToken to 0x0 to instruct fillers to use the equivalent token\n // as the originToken on the destination chain.\n address(0),\n inputAmount,\n outputAmount,\n destinationChainId,\n exclusiveRelayer,\n quoteTimestamp,\n fillDeadline,\n exclusivityDeadline,\n message\n );\n }\n}\n" + } + }, + "settings": { + "optimizer": { + "enabled": true, + "runs": 1000000 + }, + "viaIR": true, + "debug": { + "revertStrings": "strip" + }, + "outputSelection": { + "*": { + "*": [ + "abi", + "evm.bytecode", + "evm.deployedBytecode", + "evm.methodIdentifiers", + "metadata", + "devdoc", + "userdoc", + "storageLayout", + "evm.gasEstimates" + ], + "": ["ast"] + } + }, + "metadata": { + "useLiteralContent": true + } + } +} diff --git a/deployments/mainnet/SpokePoolVerifier.json b/deployments/mainnet/SpokePoolVerifier.json index 34a4e2b05..56c0e1a46 100644 --- a/deployments/mainnet/SpokePoolVerifier.json +++ b/deployments/mainnet/SpokePoolVerifier.json @@ -1,10 +1,10 @@ { - "address": "0xB4A8d45647445EA9FC3E1058096142390683dBC2", + "address": "0x4437A1Ee2dFb72954F21A44C3F0F0E2CBA5A5C27", "abi": [ { "inputs": [ { - "internalType": "contract SpokePoolInterface", + "internalType": "contract V3SpokePoolInterface", "name": "spokePool", "type": "address" }, @@ -15,12 +15,17 @@ }, { "internalType": "address", - "name": "originToken", + "name": "inputToken", "type": "address" }, { "internalType": "uint256", - "name": "amount", + "name": "inputAmount", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "outputAmount", "type": "uint256" }, { @@ -29,24 +34,29 @@ "type": "uint256" }, { - "internalType": "int64", - "name": "relayerFeePct", - "type": "int64" + "internalType": "address", + "name": "exclusiveRelayer", + "type": "address" }, { "internalType": "uint32", "name": "quoteTimestamp", "type": "uint32" }, + { + "internalType": "uint32", + "name": "fillDeadline", + "type": "uint32" + }, + { + "internalType": "uint32", + "name": "exclusivityDeadline", + "type": "uint32" + }, { "internalType": "bytes", "name": "message", "type": "bytes" - }, - { - "internalType": "uint256", - "name": "maxCount", - "type": "uint256" } ], "name": "deposit", @@ -55,43 +65,46 @@ "type": "function" } ], - "transactionHash": "0xc5229fa6ad93bfb1d3a22f3f0ac328f5522814b96ecb71b100636731aae5490a", + "transactionHash": "0x01bf4c2edf7275e22ee64aaf31fefa26e5c969007faac90b49d973ae0ed90872", "receipt": { "to": "0x4e59b44847b379578588920cA78FbF26c0B4956C", "from": "0x9A8f92a830A5cB89a3816e3D267CB7791c16b04D", "contractAddress": null, - "transactionIndex": 207, - "gasUsed": "234906", + "transactionIndex": 95, + "gasUsed": "254525", "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - "blockHash": "0xf4235ce9807aa4d1c9a7108e6014669ec74d98c0c881c691015cfe91b5d04147", - "transactionHash": "0xc5229fa6ad93bfb1d3a22f3f0ac328f5522814b96ecb71b100636731aae5490a", + "blockHash": "0xd6b0dc4b2a6f59424eb644422fb84433b08278842046ddab3304a2660fb538ab", + "transactionHash": "0x01bf4c2edf7275e22ee64aaf31fefa26e5c969007faac90b49d973ae0ed90872", "logs": [], - "blockNumber": 19510875, - "cumulativeGasUsed": "13406111", + "blockNumber": 20392299, + "cumulativeGasUsed": "10514643", "status": 1, "byzantium": true }, "args": [], - "numDeployments": 3, - "solcInputHash": "53ab13385da43753d9a657e7780a0560", - "metadata": "{\"compiler\":{\"version\":\"0.8.19+commit.7dd6d404\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"contract SpokePoolInterface\",\"name\":\"spokePool\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"internalType\":\"int64\",\"name\":\"relayerFeePct\",\"type\":\"int64\"},{\"internalType\":\"uint32\",\"name\":\"quoteTimestamp\",\"type\":\"uint32\"},{\"internalType\":\"bytes\",\"name\":\"message\",\"type\":\"bytes\"},{\"internalType\":\"uint256\",\"name\":\"maxCount\",\"type\":\"uint256\"}],\"name\":\"deposit\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"This contract must be deployed via Create2 to the same address on all chains. That way, an errant transaction sent to the wrong chain will be blocked by this contract rather than hitting a dead address. This means that this contract will not work to protect chains, like zkSync, where Create2 address derivations don't match other chains. Source: https://era.zksync.io/docs/reference/architecture/differences-with-ethereum.html#create-create2\",\"kind\":\"dev\",\"methods\":{\"deposit(address,address,address,uint256,uint256,int64,uint32,bytes,uint256)\":{\"details\":\"Protects the caller from losing their ETH (or other native token) by reverting if the SpokePool address they intended to call does not exist on this chain. Because this contract can be deployed at the same address everywhere callers should be protected even if the transaction is submitted to an unintended network. This contract should only be used for native token deposits, as this problem only exists for native tokens.\",\"params\":{\"amount\":\"Amount of tokens to deposit. Will be amount of tokens to receive less fees.\",\"destinationChainId\":\"Denotes network where user will receive funds from SpokePool by a relayer.\",\"maxCount\":\"used to protect the depositor from frontrunning to guarantee their quote remains valid. Note: this is intended to be used to pass along instructions for how a contract should use or allocate the tokens.\",\"message\":\"Arbitrary data that can be used to pass additional information to the recipient along with the tokens. Note: this is intended to be used to pass along instructions for how a contract should use or allocate the tokens.\",\"originToken\":\"Token to lock into this contract to initiate deposit.\",\"quoteTimestamp\":\"Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid to LP pool on HubPool.\",\"recipient\":\"Address to receive funds at on destination chain.\",\"relayerFeePct\":\"% of deposit amount taken out to incentivize a fast relayer.\",\"spokePool\":\"Address of the SpokePool contract that the user is intending to call.\"}}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"deposit(address,address,address,uint256,uint256,int64,uint32,bytes,uint256)\":{\"notice\":\"Passthrough function to `depositV3()` on the SpokePool contract.\"}},\"notice\":\"SpokePoolVerifier is a contract that verifies that the SpokePool exists on this chain before sending ETH to it.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/SpokePoolVerifier.sol\":\"SpokePoolVerifier\"},\"debug\":{\"revertStrings\":\"strip\"},\"evmVersion\":\"paris\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":1000000},\"remappings\":[],\"viaIR\":true},\"sources\":{\"@openzeppelin/contracts/utils/Address.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.9.0) (utils/Address.sol)\\n\\npragma solidity ^0.8.1;\\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 * Furthermore, `isContract` will also return true if the target contract within\\n * the same transaction is already scheduled for destruction by `SELFDESTRUCT`,\\n * which only has an effect at the end of a transaction.\\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 > 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://consensys.net/diligence/blog/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.8.0/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\\n */\\n function sendValue(address payable recipient, uint256 amount) internal {\\n require(address(this).balance >= amount, \\\"Address: insufficient balance\\\");\\n\\n (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 functionCallWithValue(target, data, 0, \\\"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(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, value, \\\"Address: low-level call with value failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\\n * with `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(address(this).balance >= value, \\\"Address: insufficient balance for call\\\");\\n (bool success, bytes memory returndata) = target.call{value: value}(data);\\n return verifyCallResultFromTarget(target, 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 (bool success, bytes memory returndata) = target.staticcall(data);\\n return verifyCallResultFromTarget(target, 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 (bool success, bytes memory returndata) = target.delegatecall(data);\\n return verifyCallResultFromTarget(target, success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling\\n * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.\\n *\\n * _Available since v4.8._\\n */\\n function verifyCallResultFromTarget(\\n address target,\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n if (success) {\\n if (returndata.length == 0) {\\n // only check isContract if the call was successful and the return data is empty\\n // otherwise we already know that it was a contract\\n require(isContract(target), \\\"Address: call to non-contract\\\");\\n }\\n return returndata;\\n } else {\\n _revert(returndata, errorMessage);\\n }\\n }\\n\\n /**\\n * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the\\n * revert reason or 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 _revert(returndata, errorMessage);\\n }\\n }\\n\\n function _revert(bytes memory returndata, string memory errorMessage) private pure {\\n // Look for revert reason and bubble it up if present\\n if (returndata.length > 0) {\\n // The easiest way to bubble the revert reason is using memory via assembly\\n /// @solidity memory-safe-assembly\\n assembly {\\n let returndata_size := mload(returndata)\\n revert(add(32, returndata), returndata_size)\\n }\\n } else {\\n revert(errorMessage);\\n }\\n }\\n}\\n\",\"keccak256\":\"0x006dd67219697fe68d7fbfdea512e7c4cb64a43565ed86171d67e844982da6fa\",\"license\":\"MIT\"},\"contracts/SpokePoolVerifier.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\nimport \\\"@openzeppelin/contracts/utils/Address.sol\\\";\\nimport \\\"./interfaces/SpokePoolInterface.sol\\\";\\n\\n/**\\n * @notice SpokePoolVerifier is a contract that verifies that the SpokePool exists on this chain before sending ETH to it.\\n * @dev This contract must be deployed via Create2 to the same address on all chains. That way, an errant transaction sent\\n * to the wrong chain will be blocked by this contract rather than hitting a dead address. This means that this contract\\n * will not work to protect chains, like zkSync, where Create2 address derivations don't match other chains.\\n * Source: https://era.zksync.io/docs/reference/architecture/differences-with-ethereum.html#create-create2\\n */\\ncontract SpokePoolVerifier {\\n using Address for address;\\n\\n /**\\n * @notice Passthrough function to `depositV3()` on the SpokePool contract.\\n * @dev Protects the caller from losing their ETH (or other native token) by reverting if the SpokePool address\\n * they intended to call does not exist on this chain. Because this contract can be deployed at the same address\\n * everywhere callers should be protected even if the transaction is submitted to an unintended network.\\n * This contract should only be used for native token deposits, as this problem only exists for native tokens.\\n * @param spokePool Address of the SpokePool contract that the user is intending to call.\\n * @param recipient Address to receive funds at on destination chain.\\n * @param originToken Token to lock into this contract to initiate deposit.\\n * @param amount Amount of tokens to deposit. Will be amount of tokens to receive less fees.\\n * @param destinationChainId Denotes network where user will receive funds from SpokePool by a relayer.\\n * @param relayerFeePct % of deposit amount taken out to incentivize a fast relayer.\\n * @param quoteTimestamp Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid\\n * to LP pool on HubPool.\\n * @param message Arbitrary data that can be used to pass additional information to the recipient along with the tokens.\\n * Note: this is intended to be used to pass along instructions for how a contract should use or allocate the tokens.\\n * @param maxCount used to protect the depositor from frontrunning to guarantee their quote remains valid.\\n * Note: this is intended to be used to pass along instructions for how a contract should use or allocate the tokens.\\n */\\n function deposit(\\n SpokePoolInterface spokePool,\\n address recipient,\\n address originToken,\\n uint256 amount,\\n uint256 destinationChainId,\\n int64 relayerFeePct,\\n uint32 quoteTimestamp,\\n bytes memory message,\\n uint256 maxCount\\n ) external payable {\\n require(msg.value == amount, \\\"msg.value != amount\\\");\\n require(address(spokePool).isContract(), \\\"spokePool is not a contract\\\");\\n // Set msg.sender as the depositor so that msg.sender can speed up the deposit.\\n spokePool.depositFor{ value: msg.value }(\\n msg.sender,\\n recipient,\\n originToken,\\n amount,\\n destinationChainId,\\n relayerFeePct,\\n quoteTimestamp,\\n message,\\n maxCount\\n );\\n }\\n}\\n\",\"keccak256\":\"0xfc008c31a2fde7eb0daedaa823b76931225f41ac882b6d1c515d8a38ccda60ec\",\"license\":\"BUSL-1.1\"},\"contracts/interfaces/SpokePoolInterface.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\n/**\\n * @notice Contains common data structures and functions used by all SpokePool implementations.\\n */\\ninterface SpokePoolInterface {\\n // This leaf is meant to be decoded in the SpokePool to pay out successful relayers.\\n struct RelayerRefundLeaf {\\n // This is the amount to return to the HubPool. This occurs when there is a PoolRebalanceLeaf netSendAmount that\\n // is negative. This is just the negative of this value.\\n uint256 amountToReturn;\\n // Used to verify that this is being executed on the correct destination chainId.\\n uint256 chainId;\\n // This array designates how much each of those addresses should be refunded.\\n uint256[] refundAmounts;\\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\\n uint32 leafId;\\n // The associated L2TokenAddress that these claims apply to.\\n address l2TokenAddress;\\n // Must be same length as refundAmounts and designates each address that must be refunded.\\n address[] refundAddresses;\\n }\\n\\n // Stores collection of merkle roots that can be published to this contract from the HubPool, which are referenced\\n // by \\\"data workers\\\" via inclusion proofs to execute leaves in the roots.\\n struct RootBundle {\\n // Merkle root of slow relays that were not fully filled and whose recipient is still owed funds from the LP pool.\\n bytes32 slowRelayRoot;\\n // Merkle root of relayer refunds for successful relays.\\n bytes32 relayerRefundRoot;\\n // This is a 2D bitmap tracking which leaves in the relayer refund root have been claimed, with max size of\\n // 256x(2^248) leaves per root.\\n mapping(uint256 => uint256) claimedBitmap;\\n }\\n\\n function setCrossDomainAdmin(address newCrossDomainAdmin) external;\\n\\n function setHubPool(address newHubPool) external;\\n\\n function setEnableRoute(\\n address originToken,\\n uint256 destinationChainId,\\n bool enable\\n ) external;\\n\\n function pauseDeposits(bool pause) external;\\n\\n function pauseFills(bool pause) external;\\n\\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) external;\\n\\n function emergencyDeleteRootBundle(uint256 rootBundleId) external;\\n\\n function deposit(\\n address recipient,\\n address originToken,\\n uint256 amount,\\n uint256 destinationChainId,\\n int64 relayerFeePct,\\n uint32 quoteTimestamp,\\n bytes memory message,\\n uint256 maxCount\\n ) external payable;\\n\\n function depositFor(\\n address depositor,\\n address recipient,\\n address originToken,\\n uint256 amount,\\n uint256 destinationChainId,\\n int64 relayerFeePct,\\n uint32 quoteTimestamp,\\n bytes memory message,\\n uint256 maxCount\\n ) external payable;\\n\\n function executeRelayerRefundLeaf(\\n uint32 rootBundleId,\\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\\n bytes32[] memory proof\\n ) external payable;\\n\\n function chainId() external view returns (uint256);\\n\\n error NotEOA();\\n error InvalidDepositorSignature();\\n error InvalidRelayerFeePct();\\n error MaxTransferSizeExceeded();\\n error InvalidCrossDomainAdmin();\\n error InvalidHubPool();\\n error DepositsArePaused();\\n error FillsArePaused();\\n}\\n\",\"keccak256\":\"0xc90fbd7e66e2e87e9aacbe93c20cc020cd1fc582c4fd4879807e7dc026943ea0\",\"license\":\"BUSL-1.1\"}},\"version\":1}", - "bytecode": "0x608080604052346100165761034b908161001c8239f35b600080fdfe600436101561000d57600080fd5b6000803560e01c63e0db3fcf1461002357600080fd5b610120807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103115773ffffffffffffffffffffffffffffffffffffffff600435818116810361030d576024359282841684036103095760443583811681036103055760a4358060070b81036103015760c4359063ffffffff8216820361029b5760e43567ffffffffffffffff81116102fd57366023820112156102fd57806004013567ffffffffffffffff81116102d0577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0603f81601f84011601166080016080811067ffffffffffffffff8211176102a357908a929160405280608052366024828401011161029f57602091819060240160a0376080010152606435340361029b578585163b1561029b578585163b1561029b57859694929163ffffffff91878a9896946040519a8b997f541f4f14000000000000000000000000000000000000000000000000000000008b523360048c01521660248a01521660448801526064356064880152608435608488015260070b60a48701521660c485015260e484015260805180610124850152845b8181106102805750908391827fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f6101449389858286010152610104803590850152011681010301923491165af1801561027557610233575080f35b67ffffffffffffffff81116102485760405280f35b6024827f4e487b710000000000000000000000000000000000000000000000000000000081526041600452fd5b6040513d84823e3d90fd5b60a081015187820161014401528795508694506020016101d6565b8780fd5b8280fd5b60248b7f4e487b710000000000000000000000000000000000000000000000000000000081526041600452fd5b60248a7f4e487b710000000000000000000000000000000000000000000000000000000081526041600452fd5b8880fd5b8680fd5b8580fd5b8480fd5b8380fd5b5080fdfea26469706673582212204f81f550f00970671d0755020f959a6599fd76306000e67b424172e1089b949a64736f6c63430008130033", - "deployedBytecode": "0x600436101561000d57600080fd5b6000803560e01c63e0db3fcf1461002357600080fd5b610120807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103115773ffffffffffffffffffffffffffffffffffffffff600435818116810361030d576024359282841684036103095760443583811681036103055760a4358060070b81036103015760c4359063ffffffff8216820361029b5760e43567ffffffffffffffff81116102fd57366023820112156102fd57806004013567ffffffffffffffff81116102d0577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0603f81601f84011601166080016080811067ffffffffffffffff8211176102a357908a929160405280608052366024828401011161029f57602091819060240160a0376080010152606435340361029b578585163b1561029b578585163b1561029b57859694929163ffffffff91878a9896946040519a8b997f541f4f14000000000000000000000000000000000000000000000000000000008b523360048c01521660248a01521660448801526064356064880152608435608488015260070b60a48701521660c485015260e484015260805180610124850152845b8181106102805750908391827fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f6101449389858286010152610104803590850152011681010301923491165af1801561027557610233575080f35b67ffffffffffffffff81116102485760405280f35b6024827f4e487b710000000000000000000000000000000000000000000000000000000081526041600452fd5b6040513d84823e3d90fd5b60a081015187820161014401528795508694506020016101d6565b8780fd5b8280fd5b60248b7f4e487b710000000000000000000000000000000000000000000000000000000081526041600452fd5b60248a7f4e487b710000000000000000000000000000000000000000000000000000000081526041600452fd5b8880fd5b8680fd5b8580fd5b8480fd5b8380fd5b5080fdfea26469706673582212204f81f550f00970671d0755020f959a6599fd76306000e67b424172e1089b949a64736f6c63430008130033", + "numDeployments": 5, + "solcInputHash": "783274f805324492b21545b62eb0dbfe", + "metadata": "{\"compiler\":{\"version\":\"0.8.19+commit.7dd6d404\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"contract V3SpokePoolInterface\",\"name\":\"spokePool\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"inputToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"inputAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"outputAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"exclusiveRelayer\",\"type\":\"address\"},{\"internalType\":\"uint32\",\"name\":\"quoteTimestamp\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"fillDeadline\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"exclusivityDeadline\",\"type\":\"uint32\"},{\"internalType\":\"bytes\",\"name\":\"message\",\"type\":\"bytes\"}],\"name\":\"deposit\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"}],\"devdoc\":{\"custom:security-contact\":\"bugs@across.to\",\"details\":\"This contract must be deployed via Create2 to the same address on all chains. That way, an errant transaction sent to the wrong chain will be blocked by this contract rather than hitting a dead address. This means that this contract will not work to protect chains, like zkSync, where Create2 address derivations don't match other chains. Source: https://era.zksync.io/docs/reference/architecture/differences-with-ethereum.html#create-create2\",\"kind\":\"dev\",\"methods\":{\"deposit(address,address,address,uint256,uint256,uint256,address,uint32,uint32,uint32,bytes)\":{\"details\":\"Protects the caller from losing their ETH (or other native token) by reverting if the SpokePool address they intended to call does not exist on this chain. Because this contract can be deployed at the same address everywhere callers should be protected even if the transaction is submitted to an unintended network. This contract should only be used for native token deposits, as this problem only exists for native tokens.\",\"params\":{\"destinationChainId\":\"Denotes network where user will receive funds from SpokePool by a relayer.\",\"exclusiveRelayer\":\"Address of the relayer who has exclusive rights to fill this deposit. Can be set to 0x0 if no exclusivity period is desired. If so, then must set exclusivityDeadline to 0.\",\"exclusivityDeadline\":\"Timestamp after which any relayer can fill this deposit. Must set to 0 if exclusiveRelayer is set to 0x0, and vice versa.\",\"fillDeadline\":\"Timestamp after which this deposit can no longer be filled.\",\"inputAmount\":\"Amount of tokens to deposit.\",\"inputToken\":\"Token to lock into this contract to initiate deposit.\",\"message\":\"Arbitrary data that can be used to pass additional information to the recipient along with the tokens. Note: this is intended to be used to pass along instructions for how a contract should use or allocate the tokens.\",\"outputAmount\":\"Amount of tokens to receive on destination chain.\",\"quoteTimestamp\":\"Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid to LP pool on HubPool.\",\"recipient\":\"Address to receive funds at on destination chain.\",\"spokePool\":\"Address of the SpokePool contract that the user is intending to call.\"}}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"deposit(address,address,address,uint256,uint256,uint256,address,uint32,uint32,uint32,bytes)\":{\"notice\":\"Passthrough function to `depositV3()` on the SpokePool contract.\"}},\"notice\":\"SpokePoolVerifier is a contract that verifies that the SpokePool exists on this chain before sending ETH to it.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/SpokePoolVerifier.sol\":\"SpokePoolVerifier\"},\"debug\":{\"revertStrings\":\"strip\"},\"evmVersion\":\"paris\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":1000000},\"remappings\":[],\"viaIR\":true},\"sources\":{\"@openzeppelin/contracts/utils/Address.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.9.0) (utils/Address.sol)\\n\\npragma solidity ^0.8.1;\\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 * Furthermore, `isContract` will also return true if the target contract within\\n * the same transaction is already scheduled for destruction by `SELFDESTRUCT`,\\n * which only has an effect at the end of a transaction.\\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 > 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://consensys.net/diligence/blog/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.8.0/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\\n */\\n function sendValue(address payable recipient, uint256 amount) internal {\\n require(address(this).balance >= amount, \\\"Address: insufficient balance\\\");\\n\\n (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 functionCallWithValue(target, data, 0, \\\"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(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, value, \\\"Address: low-level call with value failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\\n * with `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(address(this).balance >= value, \\\"Address: insufficient balance for call\\\");\\n (bool success, bytes memory returndata) = target.call{value: value}(data);\\n return verifyCallResultFromTarget(target, 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 (bool success, bytes memory returndata) = target.staticcall(data);\\n return verifyCallResultFromTarget(target, 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 (bool success, bytes memory returndata) = target.delegatecall(data);\\n return verifyCallResultFromTarget(target, success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling\\n * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.\\n *\\n * _Available since v4.8._\\n */\\n function verifyCallResultFromTarget(\\n address target,\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n if (success) {\\n if (returndata.length == 0) {\\n // only check isContract if the call was successful and the return data is empty\\n // otherwise we already know that it was a contract\\n require(isContract(target), \\\"Address: call to non-contract\\\");\\n }\\n return returndata;\\n } else {\\n _revert(returndata, errorMessage);\\n }\\n }\\n\\n /**\\n * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the\\n * revert reason or 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 _revert(returndata, errorMessage);\\n }\\n }\\n\\n function _revert(bytes memory returndata, string memory errorMessage) private pure {\\n // Look for revert reason and bubble it up if present\\n if (returndata.length > 0) {\\n // The easiest way to bubble the revert reason is using memory via assembly\\n /// @solidity memory-safe-assembly\\n assembly {\\n let returndata_size := mload(returndata)\\n revert(add(32, returndata), returndata_size)\\n }\\n } else {\\n revert(errorMessage);\\n }\\n }\\n}\\n\",\"keccak256\":\"0x006dd67219697fe68d7fbfdea512e7c4cb64a43565ed86171d67e844982da6fa\",\"license\":\"MIT\"},\"contracts/SpokePoolVerifier.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\nimport \\\"@openzeppelin/contracts/utils/Address.sol\\\";\\nimport \\\"./interfaces/V3SpokePoolInterface.sol\\\";\\n\\n/**\\n * @notice SpokePoolVerifier is a contract that verifies that the SpokePool exists on this chain before sending ETH to it.\\n * @dev This contract must be deployed via Create2 to the same address on all chains. That way, an errant transaction sent\\n * to the wrong chain will be blocked by this contract rather than hitting a dead address. This means that this contract\\n * will not work to protect chains, like zkSync, where Create2 address derivations don't match other chains.\\n * Source: https://era.zksync.io/docs/reference/architecture/differences-with-ethereum.html#create-create2\\n * @custom:security-contact bugs@across.to\\n */\\ncontract SpokePoolVerifier {\\n using Address for address;\\n\\n /**\\n * @notice Passthrough function to `depositV3()` on the SpokePool contract.\\n * @dev Protects the caller from losing their ETH (or other native token) by reverting if the SpokePool address\\n * they intended to call does not exist on this chain. Because this contract can be deployed at the same address\\n * everywhere callers should be protected even if the transaction is submitted to an unintended network.\\n * This contract should only be used for native token deposits, as this problem only exists for native tokens.\\n * @param spokePool Address of the SpokePool contract that the user is intending to call.\\n * @param recipient Address to receive funds at on destination chain.\\n * @param inputToken Token to lock into this contract to initiate deposit.\\n * @param inputAmount Amount of tokens to deposit.\\n * @param outputAmount Amount of tokens to receive on destination chain.\\n * @param destinationChainId Denotes network where user will receive funds from SpokePool by a relayer.\\n * @param quoteTimestamp Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid\\n * to LP pool on HubPool.\\n * @param message Arbitrary data that can be used to pass additional information to the recipient along with the tokens.\\n * Note: this is intended to be used to pass along instructions for how a contract should use or allocate the tokens.\\n * @param exclusiveRelayer Address of the relayer who has exclusive rights to fill this deposit. Can be set to\\n * 0x0 if no exclusivity period is desired. If so, then must set exclusivityDeadline to 0.\\n * @param exclusivityDeadline Timestamp after which any relayer can fill this deposit. Must set\\n * to 0 if exclusiveRelayer is set to 0x0, and vice versa.\\n * @param fillDeadline Timestamp after which this deposit can no longer be filled.\\n */\\n function deposit(\\n V3SpokePoolInterface spokePool,\\n address recipient,\\n address inputToken,\\n uint256 inputAmount,\\n uint256 outputAmount,\\n uint256 destinationChainId,\\n address exclusiveRelayer,\\n uint32 quoteTimestamp,\\n uint32 fillDeadline,\\n uint32 exclusivityDeadline,\\n bytes memory message\\n ) external payable {\\n require(msg.value == inputAmount, \\\"msg.value != amount\\\");\\n require(address(spokePool).isContract(), \\\"spokePool is not a contract\\\");\\n // Set msg.sender as the depositor so that msg.sender can speed up the deposit.\\n spokePool.depositV3{ value: msg.value }(\\n msg.sender,\\n recipient,\\n inputToken,\\n // @dev Setting outputToken to 0x0 to instruct fillers to use the equivalent token\\n // as the originToken on the destination chain.\\n address(0),\\n inputAmount,\\n outputAmount,\\n destinationChainId,\\n exclusiveRelayer,\\n quoteTimestamp,\\n fillDeadline,\\n exclusivityDeadline,\\n message\\n );\\n }\\n}\\n\",\"keccak256\":\"0xd5b1ec1b7048634a8b0a7e1e2c68ce51e410157b14778a207b64aff49bc5c6f0\",\"license\":\"BUSL-1.1\"},\"contracts/interfaces/V3SpokePoolInterface.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\n// Contains structs and functions used by SpokePool contracts to facilitate universal settlement.\\ninterface V3SpokePoolInterface {\\n /**************************************\\n * ENUMS *\\n **************************************/\\n\\n // Fill status tracks on-chain state of deposit, uniquely identified by relayHash.\\n enum FillStatus {\\n Unfilled,\\n RequestedSlowFill,\\n Filled\\n }\\n // Fill type is emitted in the FilledRelay event to assist Dataworker with determining which types of\\n // fills to refund (e.g. only fast fills) and whether a fast fill created a sow fill excess.\\n enum FillType {\\n FastFill,\\n // Fast fills are normal fills that do not replace a slow fill request.\\n ReplacedSlowFill,\\n // Replaced slow fills are fast fills that replace a slow fill request. This type is used by the Dataworker\\n // to know when to send excess funds from the SpokePool to the HubPool because they can no longer be used\\n // for a slow fill execution.\\n SlowFill\\n // Slow fills are requested via requestSlowFill and executed by executeSlowRelayLeaf after a bundle containing\\n // the slow fill is validated.\\n }\\n\\n /**************************************\\n * STRUCTS *\\n **************************************/\\n\\n // This struct represents the data to fully specify a **unique** relay submitted on this chain.\\n // This data is hashed with the chainId() and saved by the SpokePool to prevent collisions and protect against\\n // replay attacks on other chains. If any portion of this data differs, the relay is considered to be\\n // completely distinct.\\n struct V3RelayData {\\n // The address that made the deposit on the origin chain.\\n address depositor;\\n // The recipient address on the destination chain.\\n address recipient;\\n // This is the exclusive relayer who can fill the deposit before the exclusivity deadline.\\n address exclusiveRelayer;\\n // Token that is deposited on origin chain by depositor.\\n address inputToken;\\n // Token that is received on destination chain by recipient.\\n address outputToken;\\n // The amount of input token deposited by depositor.\\n uint256 inputAmount;\\n // The amount of output token to be received by recipient.\\n uint256 outputAmount;\\n // Origin chain id.\\n uint256 originChainId;\\n // The id uniquely identifying this deposit on the origin chain.\\n uint32 depositId;\\n // The timestamp on the destination chain after which this deposit can no longer be filled.\\n uint32 fillDeadline;\\n // The timestamp on the destination chain after which any relayer can fill the deposit.\\n uint32 exclusivityDeadline;\\n // Data that is forwarded to the recipient.\\n bytes message;\\n }\\n\\n // Contains parameters passed in by someone who wants to execute a slow relay leaf.\\n struct V3SlowFill {\\n V3RelayData relayData;\\n uint256 chainId;\\n uint256 updatedOutputAmount;\\n }\\n\\n // Contains information about a relay to be sent along with additional information that is not unique to the\\n // relay itself but is required to know how to process the relay. For example, \\\"updatedX\\\" fields can be used\\n // by the relayer to modify fields of the relay with the depositor's permission, and \\\"repaymentChainId\\\" is specified\\n // by the relayer to determine where to take a relayer refund, but doesn't affect the uniqueness of the relay.\\n struct V3RelayExecutionParams {\\n V3RelayData relay;\\n bytes32 relayHash;\\n uint256 updatedOutputAmount;\\n address updatedRecipient;\\n bytes updatedMessage;\\n uint256 repaymentChainId;\\n }\\n\\n // Packs together parameters emitted in FilledV3Relay because there are too many emitted otherwise.\\n // Similar to V3RelayExecutionParams, these parameters are not used to uniquely identify the deposit being\\n // filled so they don't have to be unpacked by all clients.\\n struct V3RelayExecutionEventInfo {\\n address updatedRecipient;\\n bytes updatedMessage;\\n uint256 updatedOutputAmount;\\n FillType fillType;\\n }\\n\\n /**************************************\\n * EVENTS *\\n **************************************/\\n\\n event V3FundsDeposited(\\n address inputToken,\\n address outputToken,\\n uint256 inputAmount,\\n uint256 outputAmount,\\n uint256 indexed destinationChainId,\\n uint32 indexed depositId,\\n uint32 quoteTimestamp,\\n uint32 fillDeadline,\\n uint32 exclusivityDeadline,\\n address indexed depositor,\\n address recipient,\\n address exclusiveRelayer,\\n bytes message\\n );\\n\\n event RequestedSpeedUpV3Deposit(\\n uint256 updatedOutputAmount,\\n uint32 indexed depositId,\\n address indexed depositor,\\n address updatedRecipient,\\n bytes updatedMessage,\\n bytes depositorSignature\\n );\\n\\n event FilledV3Relay(\\n address inputToken,\\n address outputToken,\\n uint256 inputAmount,\\n uint256 outputAmount,\\n uint256 repaymentChainId,\\n uint256 indexed originChainId,\\n uint32 indexed depositId,\\n uint32 fillDeadline,\\n uint32 exclusivityDeadline,\\n address exclusiveRelayer,\\n address indexed relayer,\\n address depositor,\\n address recipient,\\n bytes message,\\n V3RelayExecutionEventInfo relayExecutionInfo\\n );\\n\\n event RequestedV3SlowFill(\\n address inputToken,\\n address outputToken,\\n uint256 inputAmount,\\n uint256 outputAmount,\\n uint256 indexed originChainId,\\n uint32 indexed depositId,\\n uint32 fillDeadline,\\n uint32 exclusivityDeadline,\\n address exclusiveRelayer,\\n address depositor,\\n address recipient,\\n bytes message\\n );\\n\\n /**************************************\\n * FUNCTIONS *\\n **************************************/\\n\\n function depositV3(\\n address depositor,\\n address recipient,\\n address inputToken,\\n address outputToken,\\n uint256 inputAmount,\\n uint256 outputAmount,\\n uint256 destinationChainId,\\n address exclusiveRelayer,\\n uint32 quoteTimestamp,\\n uint32 fillDeadline,\\n uint32 exclusivityDeadline,\\n bytes calldata message\\n ) external payable;\\n\\n function depositV3Now(\\n address depositor,\\n address recipient,\\n address inputToken,\\n address outputToken,\\n uint256 inputAmount,\\n uint256 outputAmount,\\n uint256 destinationChainId,\\n address exclusiveRelayer,\\n uint32 fillDeadlineOffset,\\n uint32 exclusivityDeadline,\\n bytes calldata message\\n ) external payable;\\n\\n function speedUpV3Deposit(\\n address depositor,\\n uint32 depositId,\\n uint256 updatedOutputAmount,\\n address updatedRecipient,\\n bytes calldata updatedMessage,\\n bytes calldata depositorSignature\\n ) external;\\n\\n function fillV3Relay(V3RelayData calldata relayData, uint256 repaymentChainId) external;\\n\\n function fillV3RelayWithUpdatedDeposit(\\n V3RelayData calldata relayData,\\n uint256 repaymentChainId,\\n uint256 updatedOutputAmount,\\n address updatedRecipient,\\n bytes calldata updatedMessage,\\n bytes calldata depositorSignature\\n ) external;\\n\\n function requestV3SlowFill(V3RelayData calldata relayData) external;\\n\\n function executeV3SlowRelayLeaf(\\n V3SlowFill calldata slowFillLeaf,\\n uint32 rootBundleId,\\n bytes32[] calldata proof\\n ) external;\\n\\n /**************************************\\n * ERRORS *\\n **************************************/\\n\\n error DisabledRoute();\\n error InvalidQuoteTimestamp();\\n error InvalidFillDeadline();\\n error InvalidExclusiveRelayer();\\n error InvalidExclusivityDeadline();\\n error MsgValueDoesNotMatchInputAmount();\\n error NotExclusiveRelayer();\\n error NoSlowFillsInExclusivityWindow();\\n error RelayFilled();\\n error InvalidSlowFillRequest();\\n error ExpiredFillDeadline();\\n error InvalidMerkleProof();\\n error InvalidChainId();\\n error InvalidMerkleLeaf();\\n error ClaimedMerkleLeaf();\\n error InvalidPayoutAdjustmentPct();\\n}\\n\",\"keccak256\":\"0x374b7e9cb8afbcaec69cdbcde480676b5d927db84c7f38221331d1226af68d9d\",\"license\":\"BUSL-1.1\"}},\"version\":1}", + "bytecode": "0x60808060405234610016576103a4908161001c8239f35b600080fdfe600436101561000d57600080fd5b6000803560e01c63902e949c1461002357600080fd5b6101607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261036b5773ffffffffffffffffffffffffffffffffffffffff6004358181168103610367576024359082821682036103635760443591838316830361035f5760c435848116810361035b5760e4359063ffffffff928383168303610357576101043590848216820361035357610124359385851685036103225767ffffffffffffffff610144351161032257366023610144350112156103225767ffffffffffffffff6101443560040135116103265767ffffffffffffffff6004610144350135601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f0116608090810191821191101761032657608060046101443590810135601f81017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f011683016040529182905236910160240111610322576101443560048101359060240160a03760a06004610144350135018a90526064353403610322578887163b15610322578887163b1561032257918589979593888296818e9c60409e9b979e519e8f9d8e917f7b9392320000000000000000000000000000000000000000000000000000000083523360048401521690602401521660448c01528b60648c015260643560848c015260843560a48c015260a43560c48c01521660e48a01521661010488015216610124860152166101448401526101648301610180905260805180610184850152845b8181106103075750908391827fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f6101a49389858286010152011681010301923491165af180156102fc576102ba575080f35b67ffffffffffffffff81116102cf5760405280f35b6024827f4e487b710000000000000000000000000000000000000000000000000000000081526041600452fd5b6040513d84823e3d90fd5b60a08101518782016101a40152879550869450602001610266565b8980fd5b60248a7f4e487b710000000000000000000000000000000000000000000000000000000081526041600452fd5b8880fd5b8780fd5b8580fd5b8480fd5b8380fd5b8280fd5b80fdfea26469706673582212201ceff237e6adbd0d3f92e892f7f3f51306c23eac5f7e3f896c2c723d9e5be3a664736f6c63430008130033", + "deployedBytecode": "0x600436101561000d57600080fd5b6000803560e01c63902e949c1461002357600080fd5b6101607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261036b5773ffffffffffffffffffffffffffffffffffffffff6004358181168103610367576024359082821682036103635760443591838316830361035f5760c435848116810361035b5760e4359063ffffffff928383168303610357576101043590848216820361035357610124359385851685036103225767ffffffffffffffff610144351161032257366023610144350112156103225767ffffffffffffffff6101443560040135116103265767ffffffffffffffff6004610144350135601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f0116608090810191821191101761032657608060046101443590810135601f81017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f011683016040529182905236910160240111610322576101443560048101359060240160a03760a06004610144350135018a90526064353403610322578887163b15610322578887163b1561032257918589979593888296818e9c60409e9b979e519e8f9d8e917f7b9392320000000000000000000000000000000000000000000000000000000083523360048401521690602401521660448c01528b60648c015260643560848c015260843560a48c015260a43560c48c01521660e48a01521661010488015216610124860152166101448401526101648301610180905260805180610184850152845b8181106103075750908391827fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f6101a49389858286010152011681010301923491165af180156102fc576102ba575080f35b67ffffffffffffffff81116102cf5760405280f35b6024827f4e487b710000000000000000000000000000000000000000000000000000000081526041600452fd5b6040513d84823e3d90fd5b60a08101518782016101a40152879550869450602001610266565b8980fd5b60248a7f4e487b710000000000000000000000000000000000000000000000000000000081526041600452fd5b8880fd5b8780fd5b8580fd5b8480fd5b8380fd5b8280fd5b80fdfea26469706673582212201ceff237e6adbd0d3f92e892f7f3f51306c23eac5f7e3f896c2c723d9e5be3a664736f6c63430008130033", "devdoc": { + "custom:security-contact": "bugs@across.to", "details": "This contract must be deployed via Create2 to the same address on all chains. That way, an errant transaction sent to the wrong chain will be blocked by this contract rather than hitting a dead address. This means that this contract will not work to protect chains, like zkSync, where Create2 address derivations don't match other chains. Source: https://era.zksync.io/docs/reference/architecture/differences-with-ethereum.html#create-create2", "kind": "dev", "methods": { - "deposit(address,address,address,uint256,uint256,int64,uint32,bytes,uint256)": { + "deposit(address,address,address,uint256,uint256,uint256,address,uint32,uint32,uint32,bytes)": { "details": "Protects the caller from losing their ETH (or other native token) by reverting if the SpokePool address they intended to call does not exist on this chain. Because this contract can be deployed at the same address everywhere callers should be protected even if the transaction is submitted to an unintended network. This contract should only be used for native token deposits, as this problem only exists for native tokens.", "params": { - "amount": "Amount of tokens to deposit. Will be amount of tokens to receive less fees.", "destinationChainId": "Denotes network where user will receive funds from SpokePool by a relayer.", - "maxCount": "used to protect the depositor from frontrunning to guarantee their quote remains valid. Note: this is intended to be used to pass along instructions for how a contract should use or allocate the tokens.", + "exclusiveRelayer": "Address of the relayer who has exclusive rights to fill this deposit. Can be set to 0x0 if no exclusivity period is desired. If so, then must set exclusivityDeadline to 0.", + "exclusivityDeadline": "Timestamp after which any relayer can fill this deposit. Must set to 0 if exclusiveRelayer is set to 0x0, and vice versa.", + "fillDeadline": "Timestamp after which this deposit can no longer be filled.", + "inputAmount": "Amount of tokens to deposit.", + "inputToken": "Token to lock into this contract to initiate deposit.", "message": "Arbitrary data that can be used to pass additional information to the recipient along with the tokens. Note: this is intended to be used to pass along instructions for how a contract should use or allocate the tokens.", - "originToken": "Token to lock into this contract to initiate deposit.", + "outputAmount": "Amount of tokens to receive on destination chain.", "quoteTimestamp": "Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid to LP pool on HubPool.", "recipient": "Address to receive funds at on destination chain.", - "relayerFeePct": "% of deposit amount taken out to incentivize a fast relayer.", "spokePool": "Address of the SpokePool contract that the user is intending to call." } } @@ -101,7 +114,7 @@ "userdoc": { "kind": "user", "methods": { - "deposit(address,address,address,uint256,uint256,int64,uint32,bytes,uint256)": { + "deposit(address,address,address,uint256,uint256,uint256,address,uint32,uint32,uint32,bytes)": { "notice": "Passthrough function to `depositV3()` on the SpokePool contract." } }, diff --git a/deployments/mainnet/solcInputs/1a67233dfe969c05446730f26ab1d2c8.json b/deployments/mainnet/solcInputs/1a67233dfe969c05446730f26ab1d2c8.json new file mode 100644 index 000000000..96daeb1aa --- /dev/null +++ b/deployments/mainnet/solcInputs/1a67233dfe969c05446730f26ab1d2c8.json @@ -0,0 +1,43 @@ +{ + "language": "Solidity", + "sources": { + "@openzeppelin/contracts/utils/Address.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (utils/Address.sol)\n\npragma solidity ^0.8.1;\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 * Furthermore, `isContract` will also return true if the target contract within\n * the same transaction is already scheduled for destruction by `SELFDESTRUCT`,\n * which only has an effect at the end of a transaction.\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 > 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://consensys.net/diligence/blog/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.8.0/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n require(address(this).balance >= amount, \"Address: insufficient balance\");\n\n (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 functionCallWithValue(target, data, 0, \"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(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n return functionCallWithValue(target, data, value, \"Address: low-level call with value failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\n * with `errorMessage` as a fallback revert reason when `target` reverts.\n *\n * _Available since v3.1._\n */\n function functionCallWithValue(\n address target,\n bytes memory data,\n uint256 value,\n string memory errorMessage\n ) internal returns (bytes memory) {\n require(address(this).balance >= value, \"Address: insufficient balance for call\");\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, 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 (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, 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 (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata, errorMessage);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling\n * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.\n *\n * _Available since v4.8._\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata,\n string memory errorMessage\n ) internal view returns (bytes memory) {\n if (success) {\n if (returndata.length == 0) {\n // only check isContract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n require(isContract(target), \"Address: call to non-contract\");\n }\n return returndata;\n } else {\n _revert(returndata, errorMessage);\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the\n * revert reason or 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 _revert(returndata, errorMessage);\n }\n }\n\n function _revert(bytes memory returndata, string memory errorMessage) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length > 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert(errorMessage);\n }\n }\n}\n" + }, + "contracts/interfaces/V3SpokePoolInterface.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n// Contains structs and functions used by SpokePool contracts to facilitate universal settlement.\ninterface V3SpokePoolInterface {\n /**************************************\n * ENUMS *\n **************************************/\n\n // Fill status tracks on-chain state of deposit, uniquely identified by relayHash.\n enum FillStatus {\n Unfilled,\n RequestedSlowFill,\n Filled\n }\n // Fill type is emitted in the FilledRelay event to assist Dataworker with determining which types of\n // fills to refund (e.g. only fast fills) and whether a fast fill created a sow fill excess.\n enum FillType {\n FastFill,\n // Fast fills are normal fills that do not replace a slow fill request.\n ReplacedSlowFill,\n // Replaced slow fills are fast fills that replace a slow fill request. This type is used by the Dataworker\n // to know when to send excess funds from the SpokePool to the HubPool because they can no longer be used\n // for a slow fill execution.\n SlowFill\n // Slow fills are requested via requestSlowFill and executed by executeSlowRelayLeaf after a bundle containing\n // the slow fill is validated.\n }\n\n /**************************************\n * STRUCTS *\n **************************************/\n\n // This struct represents the data to fully specify a **unique** relay submitted on this chain.\n // This data is hashed with the chainId() and saved by the SpokePool to prevent collisions and protect against\n // replay attacks on other chains. If any portion of this data differs, the relay is considered to be\n // completely distinct.\n struct V3RelayData {\n // The address that made the deposit on the origin chain.\n address depositor;\n // The recipient address on the destination chain.\n address recipient;\n // This is the exclusive relayer who can fill the deposit before the exclusivity deadline.\n address exclusiveRelayer;\n // Token that is deposited on origin chain by depositor.\n address inputToken;\n // Token that is received on destination chain by recipient.\n address outputToken;\n // The amount of input token deposited by depositor.\n uint256 inputAmount;\n // The amount of output token to be received by recipient.\n uint256 outputAmount;\n // Origin chain id.\n uint256 originChainId;\n // The id uniquely identifying this deposit on the origin chain.\n uint32 depositId;\n // The timestamp on the destination chain after which this deposit can no longer be filled.\n uint32 fillDeadline;\n // The timestamp on the destination chain after which any relayer can fill the deposit.\n uint32 exclusivityDeadline;\n // Data that is forwarded to the recipient.\n bytes message;\n }\n\n // Contains parameters passed in by someone who wants to execute a slow relay leaf.\n struct V3SlowFill {\n V3RelayData relayData;\n uint256 chainId;\n uint256 updatedOutputAmount;\n }\n\n // Contains information about a relay to be sent along with additional information that is not unique to the\n // relay itself but is required to know how to process the relay. For example, \"updatedX\" fields can be used\n // by the relayer to modify fields of the relay with the depositor's permission, and \"repaymentChainId\" is specified\n // by the relayer to determine where to take a relayer refund, but doesn't affect the uniqueness of the relay.\n struct V3RelayExecutionParams {\n V3RelayData relay;\n bytes32 relayHash;\n uint256 updatedOutputAmount;\n address updatedRecipient;\n bytes updatedMessage;\n uint256 repaymentChainId;\n }\n\n // Packs together parameters emitted in FilledV3Relay because there are too many emitted otherwise.\n // Similar to V3RelayExecutionParams, these parameters are not used to uniquely identify the deposit being\n // filled so they don't have to be unpacked by all clients.\n struct V3RelayExecutionEventInfo {\n address updatedRecipient;\n bytes updatedMessage;\n uint256 updatedOutputAmount;\n FillType fillType;\n }\n\n /**************************************\n * EVENTS *\n **************************************/\n\n event V3FundsDeposited(\n address inputToken,\n address outputToken,\n uint256 inputAmount,\n uint256 outputAmount,\n uint256 indexed destinationChainId,\n uint32 indexed depositId,\n uint32 quoteTimestamp,\n uint32 fillDeadline,\n uint32 exclusivityDeadline,\n address indexed depositor,\n address recipient,\n address exclusiveRelayer,\n bytes message\n );\n\n event RequestedSpeedUpV3Deposit(\n uint256 updatedOutputAmount,\n uint32 indexed depositId,\n address indexed depositor,\n address updatedRecipient,\n bytes updatedMessage,\n bytes depositorSignature\n );\n\n event FilledV3Relay(\n address inputToken,\n address outputToken,\n uint256 inputAmount,\n uint256 outputAmount,\n uint256 repaymentChainId,\n uint256 indexed originChainId,\n uint32 indexed depositId,\n uint32 fillDeadline,\n uint32 exclusivityDeadline,\n address exclusiveRelayer,\n address indexed relayer,\n address depositor,\n address recipient,\n bytes message,\n V3RelayExecutionEventInfo relayExecutionInfo\n );\n\n event RequestedV3SlowFill(\n address inputToken,\n address outputToken,\n uint256 inputAmount,\n uint256 outputAmount,\n uint256 indexed originChainId,\n uint32 indexed depositId,\n uint32 fillDeadline,\n uint32 exclusivityDeadline,\n address exclusiveRelayer,\n address depositor,\n address recipient,\n bytes message\n );\n\n /**************************************\n * FUNCTIONS *\n **************************************/\n\n function depositV3(\n address depositor,\n address recipient,\n address inputToken,\n address outputToken,\n uint256 inputAmount,\n uint256 outputAmount,\n uint256 destinationChainId,\n address exclusiveRelayer,\n uint32 quoteTimestamp,\n uint32 fillDeadline,\n uint32 exclusivityDeadline,\n bytes calldata message\n ) external payable;\n\n function depositV3Now(\n address depositor,\n address recipient,\n address inputToken,\n address outputToken,\n uint256 inputAmount,\n uint256 outputAmount,\n uint256 destinationChainId,\n address exclusiveRelayer,\n uint32 fillDeadlineOffset,\n uint32 exclusivityDeadline,\n bytes calldata message\n ) external payable;\n\n function speedUpV3Deposit(\n address depositor,\n uint32 depositId,\n uint256 updatedOutputAmount,\n address updatedRecipient,\n bytes calldata updatedMessage,\n bytes calldata depositorSignature\n ) external;\n\n function fillV3Relay(V3RelayData calldata relayData, uint256 repaymentChainId) external;\n\n function fillV3RelayWithUpdatedDeposit(\n V3RelayData calldata relayData,\n uint256 repaymentChainId,\n uint256 updatedOutputAmount,\n address updatedRecipient,\n bytes calldata updatedMessage,\n bytes calldata depositorSignature\n ) external;\n\n function requestV3SlowFill(V3RelayData calldata relayData) external;\n\n function executeV3SlowRelayLeaf(\n V3SlowFill calldata slowFillLeaf,\n uint32 rootBundleId,\n bytes32[] calldata proof\n ) external;\n\n /**************************************\n * ERRORS *\n **************************************/\n\n error DisabledRoute();\n error InvalidQuoteTimestamp();\n error InvalidFillDeadline();\n error InvalidExclusiveRelayer();\n error InvalidExclusivityDeadline();\n error MsgValueDoesNotMatchInputAmount();\n error NotExclusiveRelayer();\n error NoSlowFillsInExclusivityWindow();\n error RelayFilled();\n error InvalidSlowFillRequest();\n error ExpiredFillDeadline();\n error InvalidMerkleProof();\n error InvalidChainId();\n error InvalidMerkleLeaf();\n error ClaimedMerkleLeaf();\n error InvalidPayoutAdjustmentPct();\n}\n" + }, + "contracts/SpokePoolVerifier.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/utils/Address.sol\";\nimport \"./interfaces/V3SpokePoolInterface.sol\";\n\n/**\n * @notice SpokePoolVerifier is a contract that verifies that the SpokePool exists on this chain before sending ETH to it.\n * @dev This contract must be deployed via Create2 to the same address on all chains. That way, an errant transaction sent\n * to the wrong chain will be blocked by this contract rather than hitting a dead address. This means that this contract\n * will not work to protect chains, like zkSync, where Create2 address derivations don't match other chains.\n * Source: https://era.zksync.io/docs/reference/architecture/differences-with-ethereum.html#create-create2\n * @custom:security-contact bugs@across.to\n */\ncontract SpokePoolVerifier {\n using Address for address;\n\n /**\n * @notice Passthrough function to `depositV3()` on the SpokePool contract.\n * @dev Protects the caller from losing their ETH (or other native token) by reverting if the SpokePool address\n * they intended to call does not exist on this chain. Because this contract can be deployed at the same address\n * everywhere callers should be protected even if the transaction is submitted to an unintended network.\n * This contract should only be used for native token deposits, as this problem only exists for native tokens.\n * @param spokePool Address of the SpokePool contract that the user is intending to call.\n * @param recipient Address to receive funds at on destination chain.\n * @param inputToken Token to lock into this contract to initiate deposit.\n * @param inputAmount Amount of tokens to deposit.\n * @param outputAmount Amount of tokens to receive on destination chain.\n * @param destinationChainId Denotes network where user will receive funds from SpokePool by a relayer.\n * @param quoteTimestamp Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid\n * to LP pool on HubPool.\n * @param message Arbitrary data that can be used to pass additional information to the recipient along with the tokens.\n * Note: this is intended to be used to pass along instructions for how a contract should use or allocate the tokens.\n * @param exclusiveRelayer Address of the relayer who has exclusive rights to fill this deposit. Can be set to\n * 0x0 if no exclusivity period is desired. If so, then must set exclusivityDeadline to 0.\n * @param exclusivityDeadline Timestamp after which any relayer can fill this deposit. Must set\n * to 0 if exclusiveRelayer is set to 0x0, and vice versa.\n * @param fillDeadline Timestamp after which this deposit can no longer be filled.\n */\n function deposit(\n V3SpokePoolInterface spokePool,\n address recipient,\n address inputToken,\n uint256 inputAmount,\n uint256 outputAmount,\n uint256 destinationChainId,\n uint32 quoteTimestamp,\n bytes memory message,\n address exclusiveRelayer,\n uint32 exclusivityDeadline,\n uint32 fillDeadline\n ) external payable {\n require(msg.value == inputAmount, \"msg.value != amount\");\n require(address(spokePool).isContract(), \"spokePool is not a contract\");\n // Set msg.sender as the depositor so that msg.sender can speed up the deposit.\n spokePool.depositV3{ value: msg.value }(\n msg.sender,\n recipient,\n inputToken,\n // @dev Setting outputToken to 0x0 to instruct fillers to use the equivalent token\n // as the originToken on the destination chain.\n address(0),\n inputAmount,\n outputAmount,\n destinationChainId,\n exclusiveRelayer,\n quoteTimestamp,\n fillDeadline,\n exclusivityDeadline,\n message\n );\n }\n}\n" + } + }, + "settings": { + "optimizer": { + "enabled": true, + "runs": 1000000 + }, + "viaIR": true, + "debug": { + "revertStrings": "strip" + }, + "outputSelection": { + "*": { + "*": [ + "abi", + "evm.bytecode", + "evm.deployedBytecode", + "evm.methodIdentifiers", + "metadata", + "devdoc", + "userdoc", + "storageLayout", + "evm.gasEstimates" + ], + "": ["ast"] + } + }, + "metadata": { + "useLiteralContent": true + } + } +} diff --git a/deployments/mainnet/solcInputs/783274f805324492b21545b62eb0dbfe.json b/deployments/mainnet/solcInputs/783274f805324492b21545b62eb0dbfe.json new file mode 100644 index 000000000..4bcffc07b --- /dev/null +++ b/deployments/mainnet/solcInputs/783274f805324492b21545b62eb0dbfe.json @@ -0,0 +1,43 @@ +{ + "language": "Solidity", + "sources": { + "@openzeppelin/contracts/utils/Address.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (utils/Address.sol)\n\npragma solidity ^0.8.1;\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 * Furthermore, `isContract` will also return true if the target contract within\n * the same transaction is already scheduled for destruction by `SELFDESTRUCT`,\n * which only has an effect at the end of a transaction.\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 > 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://consensys.net/diligence/blog/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.8.0/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n require(address(this).balance >= amount, \"Address: insufficient balance\");\n\n (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 functionCallWithValue(target, data, 0, \"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(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n return functionCallWithValue(target, data, value, \"Address: low-level call with value failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\n * with `errorMessage` as a fallback revert reason when `target` reverts.\n *\n * _Available since v3.1._\n */\n function functionCallWithValue(\n address target,\n bytes memory data,\n uint256 value,\n string memory errorMessage\n ) internal returns (bytes memory) {\n require(address(this).balance >= value, \"Address: insufficient balance for call\");\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, 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 (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, 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 (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata, errorMessage);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling\n * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.\n *\n * _Available since v4.8._\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata,\n string memory errorMessage\n ) internal view returns (bytes memory) {\n if (success) {\n if (returndata.length == 0) {\n // only check isContract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n require(isContract(target), \"Address: call to non-contract\");\n }\n return returndata;\n } else {\n _revert(returndata, errorMessage);\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the\n * revert reason or 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 _revert(returndata, errorMessage);\n }\n }\n\n function _revert(bytes memory returndata, string memory errorMessage) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length > 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert(errorMessage);\n }\n }\n}\n" + }, + "contracts/interfaces/V3SpokePoolInterface.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n// Contains structs and functions used by SpokePool contracts to facilitate universal settlement.\ninterface V3SpokePoolInterface {\n /**************************************\n * ENUMS *\n **************************************/\n\n // Fill status tracks on-chain state of deposit, uniquely identified by relayHash.\n enum FillStatus {\n Unfilled,\n RequestedSlowFill,\n Filled\n }\n // Fill type is emitted in the FilledRelay event to assist Dataworker with determining which types of\n // fills to refund (e.g. only fast fills) and whether a fast fill created a sow fill excess.\n enum FillType {\n FastFill,\n // Fast fills are normal fills that do not replace a slow fill request.\n ReplacedSlowFill,\n // Replaced slow fills are fast fills that replace a slow fill request. This type is used by the Dataworker\n // to know when to send excess funds from the SpokePool to the HubPool because they can no longer be used\n // for a slow fill execution.\n SlowFill\n // Slow fills are requested via requestSlowFill and executed by executeSlowRelayLeaf after a bundle containing\n // the slow fill is validated.\n }\n\n /**************************************\n * STRUCTS *\n **************************************/\n\n // This struct represents the data to fully specify a **unique** relay submitted on this chain.\n // This data is hashed with the chainId() and saved by the SpokePool to prevent collisions and protect against\n // replay attacks on other chains. If any portion of this data differs, the relay is considered to be\n // completely distinct.\n struct V3RelayData {\n // The address that made the deposit on the origin chain.\n address depositor;\n // The recipient address on the destination chain.\n address recipient;\n // This is the exclusive relayer who can fill the deposit before the exclusivity deadline.\n address exclusiveRelayer;\n // Token that is deposited on origin chain by depositor.\n address inputToken;\n // Token that is received on destination chain by recipient.\n address outputToken;\n // The amount of input token deposited by depositor.\n uint256 inputAmount;\n // The amount of output token to be received by recipient.\n uint256 outputAmount;\n // Origin chain id.\n uint256 originChainId;\n // The id uniquely identifying this deposit on the origin chain.\n uint32 depositId;\n // The timestamp on the destination chain after which this deposit can no longer be filled.\n uint32 fillDeadline;\n // The timestamp on the destination chain after which any relayer can fill the deposit.\n uint32 exclusivityDeadline;\n // Data that is forwarded to the recipient.\n bytes message;\n }\n\n // Contains parameters passed in by someone who wants to execute a slow relay leaf.\n struct V3SlowFill {\n V3RelayData relayData;\n uint256 chainId;\n uint256 updatedOutputAmount;\n }\n\n // Contains information about a relay to be sent along with additional information that is not unique to the\n // relay itself but is required to know how to process the relay. For example, \"updatedX\" fields can be used\n // by the relayer to modify fields of the relay with the depositor's permission, and \"repaymentChainId\" is specified\n // by the relayer to determine where to take a relayer refund, but doesn't affect the uniqueness of the relay.\n struct V3RelayExecutionParams {\n V3RelayData relay;\n bytes32 relayHash;\n uint256 updatedOutputAmount;\n address updatedRecipient;\n bytes updatedMessage;\n uint256 repaymentChainId;\n }\n\n // Packs together parameters emitted in FilledV3Relay because there are too many emitted otherwise.\n // Similar to V3RelayExecutionParams, these parameters are not used to uniquely identify the deposit being\n // filled so they don't have to be unpacked by all clients.\n struct V3RelayExecutionEventInfo {\n address updatedRecipient;\n bytes updatedMessage;\n uint256 updatedOutputAmount;\n FillType fillType;\n }\n\n /**************************************\n * EVENTS *\n **************************************/\n\n event V3FundsDeposited(\n address inputToken,\n address outputToken,\n uint256 inputAmount,\n uint256 outputAmount,\n uint256 indexed destinationChainId,\n uint32 indexed depositId,\n uint32 quoteTimestamp,\n uint32 fillDeadline,\n uint32 exclusivityDeadline,\n address indexed depositor,\n address recipient,\n address exclusiveRelayer,\n bytes message\n );\n\n event RequestedSpeedUpV3Deposit(\n uint256 updatedOutputAmount,\n uint32 indexed depositId,\n address indexed depositor,\n address updatedRecipient,\n bytes updatedMessage,\n bytes depositorSignature\n );\n\n event FilledV3Relay(\n address inputToken,\n address outputToken,\n uint256 inputAmount,\n uint256 outputAmount,\n uint256 repaymentChainId,\n uint256 indexed originChainId,\n uint32 indexed depositId,\n uint32 fillDeadline,\n uint32 exclusivityDeadline,\n address exclusiveRelayer,\n address indexed relayer,\n address depositor,\n address recipient,\n bytes message,\n V3RelayExecutionEventInfo relayExecutionInfo\n );\n\n event RequestedV3SlowFill(\n address inputToken,\n address outputToken,\n uint256 inputAmount,\n uint256 outputAmount,\n uint256 indexed originChainId,\n uint32 indexed depositId,\n uint32 fillDeadline,\n uint32 exclusivityDeadline,\n address exclusiveRelayer,\n address depositor,\n address recipient,\n bytes message\n );\n\n /**************************************\n * FUNCTIONS *\n **************************************/\n\n function depositV3(\n address depositor,\n address recipient,\n address inputToken,\n address outputToken,\n uint256 inputAmount,\n uint256 outputAmount,\n uint256 destinationChainId,\n address exclusiveRelayer,\n uint32 quoteTimestamp,\n uint32 fillDeadline,\n uint32 exclusivityDeadline,\n bytes calldata message\n ) external payable;\n\n function depositV3Now(\n address depositor,\n address recipient,\n address inputToken,\n address outputToken,\n uint256 inputAmount,\n uint256 outputAmount,\n uint256 destinationChainId,\n address exclusiveRelayer,\n uint32 fillDeadlineOffset,\n uint32 exclusivityDeadline,\n bytes calldata message\n ) external payable;\n\n function speedUpV3Deposit(\n address depositor,\n uint32 depositId,\n uint256 updatedOutputAmount,\n address updatedRecipient,\n bytes calldata updatedMessage,\n bytes calldata depositorSignature\n ) external;\n\n function fillV3Relay(V3RelayData calldata relayData, uint256 repaymentChainId) external;\n\n function fillV3RelayWithUpdatedDeposit(\n V3RelayData calldata relayData,\n uint256 repaymentChainId,\n uint256 updatedOutputAmount,\n address updatedRecipient,\n bytes calldata updatedMessage,\n bytes calldata depositorSignature\n ) external;\n\n function requestV3SlowFill(V3RelayData calldata relayData) external;\n\n function executeV3SlowRelayLeaf(\n V3SlowFill calldata slowFillLeaf,\n uint32 rootBundleId,\n bytes32[] calldata proof\n ) external;\n\n /**************************************\n * ERRORS *\n **************************************/\n\n error DisabledRoute();\n error InvalidQuoteTimestamp();\n error InvalidFillDeadline();\n error InvalidExclusiveRelayer();\n error InvalidExclusivityDeadline();\n error MsgValueDoesNotMatchInputAmount();\n error NotExclusiveRelayer();\n error NoSlowFillsInExclusivityWindow();\n error RelayFilled();\n error InvalidSlowFillRequest();\n error ExpiredFillDeadline();\n error InvalidMerkleProof();\n error InvalidChainId();\n error InvalidMerkleLeaf();\n error ClaimedMerkleLeaf();\n error InvalidPayoutAdjustmentPct();\n}\n" + }, + "contracts/SpokePoolVerifier.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/utils/Address.sol\";\nimport \"./interfaces/V3SpokePoolInterface.sol\";\n\n/**\n * @notice SpokePoolVerifier is a contract that verifies that the SpokePool exists on this chain before sending ETH to it.\n * @dev This contract must be deployed via Create2 to the same address on all chains. That way, an errant transaction sent\n * to the wrong chain will be blocked by this contract rather than hitting a dead address. This means that this contract\n * will not work to protect chains, like zkSync, where Create2 address derivations don't match other chains.\n * Source: https://era.zksync.io/docs/reference/architecture/differences-with-ethereum.html#create-create2\n * @custom:security-contact bugs@across.to\n */\ncontract SpokePoolVerifier {\n using Address for address;\n\n /**\n * @notice Passthrough function to `depositV3()` on the SpokePool contract.\n * @dev Protects the caller from losing their ETH (or other native token) by reverting if the SpokePool address\n * they intended to call does not exist on this chain. Because this contract can be deployed at the same address\n * everywhere callers should be protected even if the transaction is submitted to an unintended network.\n * This contract should only be used for native token deposits, as this problem only exists for native tokens.\n * @param spokePool Address of the SpokePool contract that the user is intending to call.\n * @param recipient Address to receive funds at on destination chain.\n * @param inputToken Token to lock into this contract to initiate deposit.\n * @param inputAmount Amount of tokens to deposit.\n * @param outputAmount Amount of tokens to receive on destination chain.\n * @param destinationChainId Denotes network where user will receive funds from SpokePool by a relayer.\n * @param quoteTimestamp Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid\n * to LP pool on HubPool.\n * @param message Arbitrary data that can be used to pass additional information to the recipient along with the tokens.\n * Note: this is intended to be used to pass along instructions for how a contract should use or allocate the tokens.\n * @param exclusiveRelayer Address of the relayer who has exclusive rights to fill this deposit. Can be set to\n * 0x0 if no exclusivity period is desired. If so, then must set exclusivityDeadline to 0.\n * @param exclusivityDeadline Timestamp after which any relayer can fill this deposit. Must set\n * to 0 if exclusiveRelayer is set to 0x0, and vice versa.\n * @param fillDeadline Timestamp after which this deposit can no longer be filled.\n */\n function deposit(\n V3SpokePoolInterface spokePool,\n address recipient,\n address inputToken,\n uint256 inputAmount,\n uint256 outputAmount,\n uint256 destinationChainId,\n address exclusiveRelayer,\n uint32 quoteTimestamp,\n uint32 fillDeadline,\n uint32 exclusivityDeadline,\n bytes memory message\n ) external payable {\n require(msg.value == inputAmount, \"msg.value != amount\");\n require(address(spokePool).isContract(), \"spokePool is not a contract\");\n // Set msg.sender as the depositor so that msg.sender can speed up the deposit.\n spokePool.depositV3{ value: msg.value }(\n msg.sender,\n recipient,\n inputToken,\n // @dev Setting outputToken to 0x0 to instruct fillers to use the equivalent token\n // as the originToken on the destination chain.\n address(0),\n inputAmount,\n outputAmount,\n destinationChainId,\n exclusiveRelayer,\n quoteTimestamp,\n fillDeadline,\n exclusivityDeadline,\n message\n );\n }\n}\n" + } + }, + "settings": { + "optimizer": { + "enabled": true, + "runs": 1000000 + }, + "viaIR": true, + "debug": { + "revertStrings": "strip" + }, + "outputSelection": { + "*": { + "*": [ + "abi", + "evm.bytecode", + "evm.deployedBytecode", + "evm.methodIdentifiers", + "metadata", + "devdoc", + "userdoc", + "storageLayout", + "evm.gasEstimates" + ], + "": ["ast"] + } + }, + "metadata": { + "useLiteralContent": true + } + } +} diff --git a/deployments/mode/SpokePoolVerifier.json b/deployments/mode/SpokePoolVerifier.json index 5d2b4403a..e0a92fb7e 100644 --- a/deployments/mode/SpokePoolVerifier.json +++ b/deployments/mode/SpokePoolVerifier.json @@ -1,10 +1,10 @@ { - "address": "0xB4A8d45647445EA9FC3E1058096142390683dBC2", + "address": "0x4437A1Ee2dFb72954F21A44C3F0F0E2CBA5A5C27", "abi": [ { "inputs": [ { - "internalType": "contract SpokePoolInterface", + "internalType": "contract V3SpokePoolInterface", "name": "spokePool", "type": "address" }, @@ -15,12 +15,17 @@ }, { "internalType": "address", - "name": "originToken", + "name": "inputToken", "type": "address" }, { "internalType": "uint256", - "name": "amount", + "name": "inputAmount", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "outputAmount", "type": "uint256" }, { @@ -29,24 +34,29 @@ "type": "uint256" }, { - "internalType": "int64", - "name": "relayerFeePct", - "type": "int64" + "internalType": "address", + "name": "exclusiveRelayer", + "type": "address" }, { "internalType": "uint32", "name": "quoteTimestamp", "type": "uint32" }, + { + "internalType": "uint32", + "name": "fillDeadline", + "type": "uint32" + }, + { + "internalType": "uint32", + "name": "exclusivityDeadline", + "type": "uint32" + }, { "internalType": "bytes", "name": "message", "type": "bytes" - }, - { - "internalType": "uint256", - "name": "maxCount", - "type": "uint256" } ], "name": "deposit", @@ -55,43 +65,46 @@ "type": "function" } ], - "transactionHash": "0x0800c54bb89c3adf14ec9fec436987d6a61eef241fd8430f5bae707112817621", + "transactionHash": "0x5c100fd484d24447694871ea8dc968430f30bc1fc38bf3ec7d3bd5d3cae3391b", "receipt": { "to": "0x4e59b44847b379578588920cA78FbF26c0B4956C", "from": "0x9A8f92a830A5cB89a3816e3D267CB7791c16b04D", "contractAddress": null, - "transactionIndex": 6, - "gasUsed": "234906", + "transactionIndex": 3, + "gasUsed": "254525", "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - "blockHash": "0xb601b3432768626f295cbe8f660bc3f2af4937284b8331d5642c82e448e8624c", - "transactionHash": "0x0800c54bb89c3adf14ec9fec436987d6a61eef241fd8430f5bae707112817621", + "blockHash": "0x41b6366706969b6e601dca86ec7521e4348c82c720483f3ebf1d2921ee25a7bf", + "transactionHash": "0x5c100fd484d24447694871ea8dc968430f30bc1fc38bf3ec7d3bd5d3cae3391b", "logs": [], - "blockNumber": 8038567, - "cumulativeGasUsed": "822434", + "blockNumber": 10924056, + "cumulativeGasUsed": "1416671", "status": 1, "byzantium": true }, "args": [], - "numDeployments": 1, - "solcInputHash": "53ab13385da43753d9a657e7780a0560", - "metadata": "{\"compiler\":{\"version\":\"0.8.19+commit.7dd6d404\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"contract SpokePoolInterface\",\"name\":\"spokePool\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"internalType\":\"int64\",\"name\":\"relayerFeePct\",\"type\":\"int64\"},{\"internalType\":\"uint32\",\"name\":\"quoteTimestamp\",\"type\":\"uint32\"},{\"internalType\":\"bytes\",\"name\":\"message\",\"type\":\"bytes\"},{\"internalType\":\"uint256\",\"name\":\"maxCount\",\"type\":\"uint256\"}],\"name\":\"deposit\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"This contract must be deployed via Create2 to the same address on all chains. That way, an errant transaction sent to the wrong chain will be blocked by this contract rather than hitting a dead address. This means that this contract will not work to protect chains, like zkSync, where Create2 address derivations don't match other chains. Source: https://era.zksync.io/docs/reference/architecture/differences-with-ethereum.html#create-create2\",\"kind\":\"dev\",\"methods\":{\"deposit(address,address,address,uint256,uint256,int64,uint32,bytes,uint256)\":{\"details\":\"Protects the caller from losing their ETH (or other native token) by reverting if the SpokePool address they intended to call does not exist on this chain. Because this contract can be deployed at the same address everywhere callers should be protected even if the transaction is submitted to an unintended network. This contract should only be used for native token deposits, as this problem only exists for native tokens.\",\"params\":{\"amount\":\"Amount of tokens to deposit. Will be amount of tokens to receive less fees.\",\"destinationChainId\":\"Denotes network where user will receive funds from SpokePool by a relayer.\",\"maxCount\":\"used to protect the depositor from frontrunning to guarantee their quote remains valid. Note: this is intended to be used to pass along instructions for how a contract should use or allocate the tokens.\",\"message\":\"Arbitrary data that can be used to pass additional information to the recipient along with the tokens. Note: this is intended to be used to pass along instructions for how a contract should use or allocate the tokens.\",\"originToken\":\"Token to lock into this contract to initiate deposit.\",\"quoteTimestamp\":\"Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid to LP pool on HubPool.\",\"recipient\":\"Address to receive funds at on destination chain.\",\"relayerFeePct\":\"% of deposit amount taken out to incentivize a fast relayer.\",\"spokePool\":\"Address of the SpokePool contract that the user is intending to call.\"}}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"deposit(address,address,address,uint256,uint256,int64,uint32,bytes,uint256)\":{\"notice\":\"Passthrough function to `depositV3()` on the SpokePool contract.\"}},\"notice\":\"SpokePoolVerifier is a contract that verifies that the SpokePool exists on this chain before sending ETH to it.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/SpokePoolVerifier.sol\":\"SpokePoolVerifier\"},\"debug\":{\"revertStrings\":\"strip\"},\"evmVersion\":\"paris\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":1000000},\"remappings\":[],\"viaIR\":true},\"sources\":{\"@openzeppelin/contracts/utils/Address.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.9.0) (utils/Address.sol)\\n\\npragma solidity ^0.8.1;\\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 * Furthermore, `isContract` will also return true if the target contract within\\n * the same transaction is already scheduled for destruction by `SELFDESTRUCT`,\\n * which only has an effect at the end of a transaction.\\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 > 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://consensys.net/diligence/blog/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.8.0/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\\n */\\n function sendValue(address payable recipient, uint256 amount) internal {\\n require(address(this).balance >= amount, \\\"Address: insufficient balance\\\");\\n\\n (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 functionCallWithValue(target, data, 0, \\\"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(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, value, \\\"Address: low-level call with value failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\\n * with `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(address(this).balance >= value, \\\"Address: insufficient balance for call\\\");\\n (bool success, bytes memory returndata) = target.call{value: value}(data);\\n return verifyCallResultFromTarget(target, 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 (bool success, bytes memory returndata) = target.staticcall(data);\\n return verifyCallResultFromTarget(target, 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 (bool success, bytes memory returndata) = target.delegatecall(data);\\n return verifyCallResultFromTarget(target, success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling\\n * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.\\n *\\n * _Available since v4.8._\\n */\\n function verifyCallResultFromTarget(\\n address target,\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n if (success) {\\n if (returndata.length == 0) {\\n // only check isContract if the call was successful and the return data is empty\\n // otherwise we already know that it was a contract\\n require(isContract(target), \\\"Address: call to non-contract\\\");\\n }\\n return returndata;\\n } else {\\n _revert(returndata, errorMessage);\\n }\\n }\\n\\n /**\\n * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the\\n * revert reason or 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 _revert(returndata, errorMessage);\\n }\\n }\\n\\n function _revert(bytes memory returndata, string memory errorMessage) private pure {\\n // Look for revert reason and bubble it up if present\\n if (returndata.length > 0) {\\n // The easiest way to bubble the revert reason is using memory via assembly\\n /// @solidity memory-safe-assembly\\n assembly {\\n let returndata_size := mload(returndata)\\n revert(add(32, returndata), returndata_size)\\n }\\n } else {\\n revert(errorMessage);\\n }\\n }\\n}\\n\",\"keccak256\":\"0x006dd67219697fe68d7fbfdea512e7c4cb64a43565ed86171d67e844982da6fa\",\"license\":\"MIT\"},\"contracts/SpokePoolVerifier.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\nimport \\\"@openzeppelin/contracts/utils/Address.sol\\\";\\nimport \\\"./interfaces/SpokePoolInterface.sol\\\";\\n\\n/**\\n * @notice SpokePoolVerifier is a contract that verifies that the SpokePool exists on this chain before sending ETH to it.\\n * @dev This contract must be deployed via Create2 to the same address on all chains. That way, an errant transaction sent\\n * to the wrong chain will be blocked by this contract rather than hitting a dead address. This means that this contract\\n * will not work to protect chains, like zkSync, where Create2 address derivations don't match other chains.\\n * Source: https://era.zksync.io/docs/reference/architecture/differences-with-ethereum.html#create-create2\\n */\\ncontract SpokePoolVerifier {\\n using Address for address;\\n\\n /**\\n * @notice Passthrough function to `depositV3()` on the SpokePool contract.\\n * @dev Protects the caller from losing their ETH (or other native token) by reverting if the SpokePool address\\n * they intended to call does not exist on this chain. Because this contract can be deployed at the same address\\n * everywhere callers should be protected even if the transaction is submitted to an unintended network.\\n * This contract should only be used for native token deposits, as this problem only exists for native tokens.\\n * @param spokePool Address of the SpokePool contract that the user is intending to call.\\n * @param recipient Address to receive funds at on destination chain.\\n * @param originToken Token to lock into this contract to initiate deposit.\\n * @param amount Amount of tokens to deposit. Will be amount of tokens to receive less fees.\\n * @param destinationChainId Denotes network where user will receive funds from SpokePool by a relayer.\\n * @param relayerFeePct % of deposit amount taken out to incentivize a fast relayer.\\n * @param quoteTimestamp Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid\\n * to LP pool on HubPool.\\n * @param message Arbitrary data that can be used to pass additional information to the recipient along with the tokens.\\n * Note: this is intended to be used to pass along instructions for how a contract should use or allocate the tokens.\\n * @param maxCount used to protect the depositor from frontrunning to guarantee their quote remains valid.\\n * Note: this is intended to be used to pass along instructions for how a contract should use or allocate the tokens.\\n */\\n function deposit(\\n SpokePoolInterface spokePool,\\n address recipient,\\n address originToken,\\n uint256 amount,\\n uint256 destinationChainId,\\n int64 relayerFeePct,\\n uint32 quoteTimestamp,\\n bytes memory message,\\n uint256 maxCount\\n ) external payable {\\n require(msg.value == amount, \\\"msg.value != amount\\\");\\n require(address(spokePool).isContract(), \\\"spokePool is not a contract\\\");\\n // Set msg.sender as the depositor so that msg.sender can speed up the deposit.\\n spokePool.depositFor{ value: msg.value }(\\n msg.sender,\\n recipient,\\n originToken,\\n amount,\\n destinationChainId,\\n relayerFeePct,\\n quoteTimestamp,\\n message,\\n maxCount\\n );\\n }\\n}\\n\",\"keccak256\":\"0xfc008c31a2fde7eb0daedaa823b76931225f41ac882b6d1c515d8a38ccda60ec\",\"license\":\"BUSL-1.1\"},\"contracts/interfaces/SpokePoolInterface.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\n/**\\n * @notice Contains common data structures and functions used by all SpokePool implementations.\\n */\\ninterface SpokePoolInterface {\\n // This leaf is meant to be decoded in the SpokePool to pay out successful relayers.\\n struct RelayerRefundLeaf {\\n // This is the amount to return to the HubPool. This occurs when there is a PoolRebalanceLeaf netSendAmount that\\n // is negative. This is just the negative of this value.\\n uint256 amountToReturn;\\n // Used to verify that this is being executed on the correct destination chainId.\\n uint256 chainId;\\n // This array designates how much each of those addresses should be refunded.\\n uint256[] refundAmounts;\\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\\n uint32 leafId;\\n // The associated L2TokenAddress that these claims apply to.\\n address l2TokenAddress;\\n // Must be same length as refundAmounts and designates each address that must be refunded.\\n address[] refundAddresses;\\n }\\n\\n // Stores collection of merkle roots that can be published to this contract from the HubPool, which are referenced\\n // by \\\"data workers\\\" via inclusion proofs to execute leaves in the roots.\\n struct RootBundle {\\n // Merkle root of slow relays that were not fully filled and whose recipient is still owed funds from the LP pool.\\n bytes32 slowRelayRoot;\\n // Merkle root of relayer refunds for successful relays.\\n bytes32 relayerRefundRoot;\\n // This is a 2D bitmap tracking which leaves in the relayer refund root have been claimed, with max size of\\n // 256x(2^248) leaves per root.\\n mapping(uint256 => uint256) claimedBitmap;\\n }\\n\\n function setCrossDomainAdmin(address newCrossDomainAdmin) external;\\n\\n function setHubPool(address newHubPool) external;\\n\\n function setEnableRoute(\\n address originToken,\\n uint256 destinationChainId,\\n bool enable\\n ) external;\\n\\n function pauseDeposits(bool pause) external;\\n\\n function pauseFills(bool pause) external;\\n\\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) external;\\n\\n function emergencyDeleteRootBundle(uint256 rootBundleId) external;\\n\\n function deposit(\\n address recipient,\\n address originToken,\\n uint256 amount,\\n uint256 destinationChainId,\\n int64 relayerFeePct,\\n uint32 quoteTimestamp,\\n bytes memory message,\\n uint256 maxCount\\n ) external payable;\\n\\n function depositFor(\\n address depositor,\\n address recipient,\\n address originToken,\\n uint256 amount,\\n uint256 destinationChainId,\\n int64 relayerFeePct,\\n uint32 quoteTimestamp,\\n bytes memory message,\\n uint256 maxCount\\n ) external payable;\\n\\n function executeRelayerRefundLeaf(\\n uint32 rootBundleId,\\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\\n bytes32[] memory proof\\n ) external payable;\\n\\n function chainId() external view returns (uint256);\\n\\n error NotEOA();\\n error InvalidDepositorSignature();\\n error InvalidRelayerFeePct();\\n error MaxTransferSizeExceeded();\\n error InvalidCrossDomainAdmin();\\n error InvalidHubPool();\\n error DepositsArePaused();\\n error FillsArePaused();\\n}\\n\",\"keccak256\":\"0xc90fbd7e66e2e87e9aacbe93c20cc020cd1fc582c4fd4879807e7dc026943ea0\",\"license\":\"BUSL-1.1\"}},\"version\":1}", - "bytecode": "0x608080604052346100165761034b908161001c8239f35b600080fdfe600436101561000d57600080fd5b6000803560e01c63e0db3fcf1461002357600080fd5b610120807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103115773ffffffffffffffffffffffffffffffffffffffff600435818116810361030d576024359282841684036103095760443583811681036103055760a4358060070b81036103015760c4359063ffffffff8216820361029b5760e43567ffffffffffffffff81116102fd57366023820112156102fd57806004013567ffffffffffffffff81116102d0577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0603f81601f84011601166080016080811067ffffffffffffffff8211176102a357908a929160405280608052366024828401011161029f57602091819060240160a0376080010152606435340361029b578585163b1561029b578585163b1561029b57859694929163ffffffff91878a9896946040519a8b997f541f4f14000000000000000000000000000000000000000000000000000000008b523360048c01521660248a01521660448801526064356064880152608435608488015260070b60a48701521660c485015260e484015260805180610124850152845b8181106102805750908391827fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f6101449389858286010152610104803590850152011681010301923491165af1801561027557610233575080f35b67ffffffffffffffff81116102485760405280f35b6024827f4e487b710000000000000000000000000000000000000000000000000000000081526041600452fd5b6040513d84823e3d90fd5b60a081015187820161014401528795508694506020016101d6565b8780fd5b8280fd5b60248b7f4e487b710000000000000000000000000000000000000000000000000000000081526041600452fd5b60248a7f4e487b710000000000000000000000000000000000000000000000000000000081526041600452fd5b8880fd5b8680fd5b8580fd5b8480fd5b8380fd5b5080fdfea26469706673582212204f81f550f00970671d0755020f959a6599fd76306000e67b424172e1089b949a64736f6c63430008130033", - "deployedBytecode": "0x600436101561000d57600080fd5b6000803560e01c63e0db3fcf1461002357600080fd5b610120807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103115773ffffffffffffffffffffffffffffffffffffffff600435818116810361030d576024359282841684036103095760443583811681036103055760a4358060070b81036103015760c4359063ffffffff8216820361029b5760e43567ffffffffffffffff81116102fd57366023820112156102fd57806004013567ffffffffffffffff81116102d0577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0603f81601f84011601166080016080811067ffffffffffffffff8211176102a357908a929160405280608052366024828401011161029f57602091819060240160a0376080010152606435340361029b578585163b1561029b578585163b1561029b57859694929163ffffffff91878a9896946040519a8b997f541f4f14000000000000000000000000000000000000000000000000000000008b523360048c01521660248a01521660448801526064356064880152608435608488015260070b60a48701521660c485015260e484015260805180610124850152845b8181106102805750908391827fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f6101449389858286010152610104803590850152011681010301923491165af1801561027557610233575080f35b67ffffffffffffffff81116102485760405280f35b6024827f4e487b710000000000000000000000000000000000000000000000000000000081526041600452fd5b6040513d84823e3d90fd5b60a081015187820161014401528795508694506020016101d6565b8780fd5b8280fd5b60248b7f4e487b710000000000000000000000000000000000000000000000000000000081526041600452fd5b60248a7f4e487b710000000000000000000000000000000000000000000000000000000081526041600452fd5b8880fd5b8680fd5b8580fd5b8480fd5b8380fd5b5080fdfea26469706673582212204f81f550f00970671d0755020f959a6599fd76306000e67b424172e1089b949a64736f6c63430008130033", + "numDeployments": 3, + "solcInputHash": "783274f805324492b21545b62eb0dbfe", + "metadata": "{\"compiler\":{\"version\":\"0.8.19+commit.7dd6d404\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"contract V3SpokePoolInterface\",\"name\":\"spokePool\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"inputToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"inputAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"outputAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"exclusiveRelayer\",\"type\":\"address\"},{\"internalType\":\"uint32\",\"name\":\"quoteTimestamp\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"fillDeadline\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"exclusivityDeadline\",\"type\":\"uint32\"},{\"internalType\":\"bytes\",\"name\":\"message\",\"type\":\"bytes\"}],\"name\":\"deposit\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"}],\"devdoc\":{\"custom:security-contact\":\"bugs@across.to\",\"details\":\"This contract must be deployed via Create2 to the same address on all chains. That way, an errant transaction sent to the wrong chain will be blocked by this contract rather than hitting a dead address. This means that this contract will not work to protect chains, like zkSync, where Create2 address derivations don't match other chains. Source: https://era.zksync.io/docs/reference/architecture/differences-with-ethereum.html#create-create2\",\"kind\":\"dev\",\"methods\":{\"deposit(address,address,address,uint256,uint256,uint256,address,uint32,uint32,uint32,bytes)\":{\"details\":\"Protects the caller from losing their ETH (or other native token) by reverting if the SpokePool address they intended to call does not exist on this chain. Because this contract can be deployed at the same address everywhere callers should be protected even if the transaction is submitted to an unintended network. This contract should only be used for native token deposits, as this problem only exists for native tokens.\",\"params\":{\"destinationChainId\":\"Denotes network where user will receive funds from SpokePool by a relayer.\",\"exclusiveRelayer\":\"Address of the relayer who has exclusive rights to fill this deposit. Can be set to 0x0 if no exclusivity period is desired. If so, then must set exclusivityDeadline to 0.\",\"exclusivityDeadline\":\"Timestamp after which any relayer can fill this deposit. Must set to 0 if exclusiveRelayer is set to 0x0, and vice versa.\",\"fillDeadline\":\"Timestamp after which this deposit can no longer be filled.\",\"inputAmount\":\"Amount of tokens to deposit.\",\"inputToken\":\"Token to lock into this contract to initiate deposit.\",\"message\":\"Arbitrary data that can be used to pass additional information to the recipient along with the tokens. Note: this is intended to be used to pass along instructions for how a contract should use or allocate the tokens.\",\"outputAmount\":\"Amount of tokens to receive on destination chain.\",\"quoteTimestamp\":\"Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid to LP pool on HubPool.\",\"recipient\":\"Address to receive funds at on destination chain.\",\"spokePool\":\"Address of the SpokePool contract that the user is intending to call.\"}}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"deposit(address,address,address,uint256,uint256,uint256,address,uint32,uint32,uint32,bytes)\":{\"notice\":\"Passthrough function to `depositV3()` on the SpokePool contract.\"}},\"notice\":\"SpokePoolVerifier is a contract that verifies that the SpokePool exists on this chain before sending ETH to it.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/SpokePoolVerifier.sol\":\"SpokePoolVerifier\"},\"debug\":{\"revertStrings\":\"strip\"},\"evmVersion\":\"paris\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":1000000},\"remappings\":[],\"viaIR\":true},\"sources\":{\"@openzeppelin/contracts/utils/Address.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.9.0) (utils/Address.sol)\\n\\npragma solidity ^0.8.1;\\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 * Furthermore, `isContract` will also return true if the target contract within\\n * the same transaction is already scheduled for destruction by `SELFDESTRUCT`,\\n * which only has an effect at the end of a transaction.\\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 > 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://consensys.net/diligence/blog/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.8.0/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\\n */\\n function sendValue(address payable recipient, uint256 amount) internal {\\n require(address(this).balance >= amount, \\\"Address: insufficient balance\\\");\\n\\n (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 functionCallWithValue(target, data, 0, \\\"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(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, value, \\\"Address: low-level call with value failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\\n * with `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(address(this).balance >= value, \\\"Address: insufficient balance for call\\\");\\n (bool success, bytes memory returndata) = target.call{value: value}(data);\\n return verifyCallResultFromTarget(target, 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 (bool success, bytes memory returndata) = target.staticcall(data);\\n return verifyCallResultFromTarget(target, 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 (bool success, bytes memory returndata) = target.delegatecall(data);\\n return verifyCallResultFromTarget(target, success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling\\n * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.\\n *\\n * _Available since v4.8._\\n */\\n function verifyCallResultFromTarget(\\n address target,\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n if (success) {\\n if (returndata.length == 0) {\\n // only check isContract if the call was successful and the return data is empty\\n // otherwise we already know that it was a contract\\n require(isContract(target), \\\"Address: call to non-contract\\\");\\n }\\n return returndata;\\n } else {\\n _revert(returndata, errorMessage);\\n }\\n }\\n\\n /**\\n * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the\\n * revert reason or 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 _revert(returndata, errorMessage);\\n }\\n }\\n\\n function _revert(bytes memory returndata, string memory errorMessage) private pure {\\n // Look for revert reason and bubble it up if present\\n if (returndata.length > 0) {\\n // The easiest way to bubble the revert reason is using memory via assembly\\n /// @solidity memory-safe-assembly\\n assembly {\\n let returndata_size := mload(returndata)\\n revert(add(32, returndata), returndata_size)\\n }\\n } else {\\n revert(errorMessage);\\n }\\n }\\n}\\n\",\"keccak256\":\"0x006dd67219697fe68d7fbfdea512e7c4cb64a43565ed86171d67e844982da6fa\",\"license\":\"MIT\"},\"contracts/SpokePoolVerifier.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\nimport \\\"@openzeppelin/contracts/utils/Address.sol\\\";\\nimport \\\"./interfaces/V3SpokePoolInterface.sol\\\";\\n\\n/**\\n * @notice SpokePoolVerifier is a contract that verifies that the SpokePool exists on this chain before sending ETH to it.\\n * @dev This contract must be deployed via Create2 to the same address on all chains. That way, an errant transaction sent\\n * to the wrong chain will be blocked by this contract rather than hitting a dead address. This means that this contract\\n * will not work to protect chains, like zkSync, where Create2 address derivations don't match other chains.\\n * Source: https://era.zksync.io/docs/reference/architecture/differences-with-ethereum.html#create-create2\\n * @custom:security-contact bugs@across.to\\n */\\ncontract SpokePoolVerifier {\\n using Address for address;\\n\\n /**\\n * @notice Passthrough function to `depositV3()` on the SpokePool contract.\\n * @dev Protects the caller from losing their ETH (or other native token) by reverting if the SpokePool address\\n * they intended to call does not exist on this chain. Because this contract can be deployed at the same address\\n * everywhere callers should be protected even if the transaction is submitted to an unintended network.\\n * This contract should only be used for native token deposits, as this problem only exists for native tokens.\\n * @param spokePool Address of the SpokePool contract that the user is intending to call.\\n * @param recipient Address to receive funds at on destination chain.\\n * @param inputToken Token to lock into this contract to initiate deposit.\\n * @param inputAmount Amount of tokens to deposit.\\n * @param outputAmount Amount of tokens to receive on destination chain.\\n * @param destinationChainId Denotes network where user will receive funds from SpokePool by a relayer.\\n * @param quoteTimestamp Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid\\n * to LP pool on HubPool.\\n * @param message Arbitrary data that can be used to pass additional information to the recipient along with the tokens.\\n * Note: this is intended to be used to pass along instructions for how a contract should use or allocate the tokens.\\n * @param exclusiveRelayer Address of the relayer who has exclusive rights to fill this deposit. Can be set to\\n * 0x0 if no exclusivity period is desired. If so, then must set exclusivityDeadline to 0.\\n * @param exclusivityDeadline Timestamp after which any relayer can fill this deposit. Must set\\n * to 0 if exclusiveRelayer is set to 0x0, and vice versa.\\n * @param fillDeadline Timestamp after which this deposit can no longer be filled.\\n */\\n function deposit(\\n V3SpokePoolInterface spokePool,\\n address recipient,\\n address inputToken,\\n uint256 inputAmount,\\n uint256 outputAmount,\\n uint256 destinationChainId,\\n address exclusiveRelayer,\\n uint32 quoteTimestamp,\\n uint32 fillDeadline,\\n uint32 exclusivityDeadline,\\n bytes memory message\\n ) external payable {\\n require(msg.value == inputAmount, \\\"msg.value != amount\\\");\\n require(address(spokePool).isContract(), \\\"spokePool is not a contract\\\");\\n // Set msg.sender as the depositor so that msg.sender can speed up the deposit.\\n spokePool.depositV3{ value: msg.value }(\\n msg.sender,\\n recipient,\\n inputToken,\\n // @dev Setting outputToken to 0x0 to instruct fillers to use the equivalent token\\n // as the originToken on the destination chain.\\n address(0),\\n inputAmount,\\n outputAmount,\\n destinationChainId,\\n exclusiveRelayer,\\n quoteTimestamp,\\n fillDeadline,\\n exclusivityDeadline,\\n message\\n );\\n }\\n}\\n\",\"keccak256\":\"0xd5b1ec1b7048634a8b0a7e1e2c68ce51e410157b14778a207b64aff49bc5c6f0\",\"license\":\"BUSL-1.1\"},\"contracts/interfaces/V3SpokePoolInterface.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\n// Contains structs and functions used by SpokePool contracts to facilitate universal settlement.\\ninterface V3SpokePoolInterface {\\n /**************************************\\n * ENUMS *\\n **************************************/\\n\\n // Fill status tracks on-chain state of deposit, uniquely identified by relayHash.\\n enum FillStatus {\\n Unfilled,\\n RequestedSlowFill,\\n Filled\\n }\\n // Fill type is emitted in the FilledRelay event to assist Dataworker with determining which types of\\n // fills to refund (e.g. only fast fills) and whether a fast fill created a sow fill excess.\\n enum FillType {\\n FastFill,\\n // Fast fills are normal fills that do not replace a slow fill request.\\n ReplacedSlowFill,\\n // Replaced slow fills are fast fills that replace a slow fill request. This type is used by the Dataworker\\n // to know when to send excess funds from the SpokePool to the HubPool because they can no longer be used\\n // for a slow fill execution.\\n SlowFill\\n // Slow fills are requested via requestSlowFill and executed by executeSlowRelayLeaf after a bundle containing\\n // the slow fill is validated.\\n }\\n\\n /**************************************\\n * STRUCTS *\\n **************************************/\\n\\n // This struct represents the data to fully specify a **unique** relay submitted on this chain.\\n // This data is hashed with the chainId() and saved by the SpokePool to prevent collisions and protect against\\n // replay attacks on other chains. If any portion of this data differs, the relay is considered to be\\n // completely distinct.\\n struct V3RelayData {\\n // The address that made the deposit on the origin chain.\\n address depositor;\\n // The recipient address on the destination chain.\\n address recipient;\\n // This is the exclusive relayer who can fill the deposit before the exclusivity deadline.\\n address exclusiveRelayer;\\n // Token that is deposited on origin chain by depositor.\\n address inputToken;\\n // Token that is received on destination chain by recipient.\\n address outputToken;\\n // The amount of input token deposited by depositor.\\n uint256 inputAmount;\\n // The amount of output token to be received by recipient.\\n uint256 outputAmount;\\n // Origin chain id.\\n uint256 originChainId;\\n // The id uniquely identifying this deposit on the origin chain.\\n uint32 depositId;\\n // The timestamp on the destination chain after which this deposit can no longer be filled.\\n uint32 fillDeadline;\\n // The timestamp on the destination chain after which any relayer can fill the deposit.\\n uint32 exclusivityDeadline;\\n // Data that is forwarded to the recipient.\\n bytes message;\\n }\\n\\n // Contains parameters passed in by someone who wants to execute a slow relay leaf.\\n struct V3SlowFill {\\n V3RelayData relayData;\\n uint256 chainId;\\n uint256 updatedOutputAmount;\\n }\\n\\n // Contains information about a relay to be sent along with additional information that is not unique to the\\n // relay itself but is required to know how to process the relay. For example, \\\"updatedX\\\" fields can be used\\n // by the relayer to modify fields of the relay with the depositor's permission, and \\\"repaymentChainId\\\" is specified\\n // by the relayer to determine where to take a relayer refund, but doesn't affect the uniqueness of the relay.\\n struct V3RelayExecutionParams {\\n V3RelayData relay;\\n bytes32 relayHash;\\n uint256 updatedOutputAmount;\\n address updatedRecipient;\\n bytes updatedMessage;\\n uint256 repaymentChainId;\\n }\\n\\n // Packs together parameters emitted in FilledV3Relay because there are too many emitted otherwise.\\n // Similar to V3RelayExecutionParams, these parameters are not used to uniquely identify the deposit being\\n // filled so they don't have to be unpacked by all clients.\\n struct V3RelayExecutionEventInfo {\\n address updatedRecipient;\\n bytes updatedMessage;\\n uint256 updatedOutputAmount;\\n FillType fillType;\\n }\\n\\n /**************************************\\n * EVENTS *\\n **************************************/\\n\\n event V3FundsDeposited(\\n address inputToken,\\n address outputToken,\\n uint256 inputAmount,\\n uint256 outputAmount,\\n uint256 indexed destinationChainId,\\n uint32 indexed depositId,\\n uint32 quoteTimestamp,\\n uint32 fillDeadline,\\n uint32 exclusivityDeadline,\\n address indexed depositor,\\n address recipient,\\n address exclusiveRelayer,\\n bytes message\\n );\\n\\n event RequestedSpeedUpV3Deposit(\\n uint256 updatedOutputAmount,\\n uint32 indexed depositId,\\n address indexed depositor,\\n address updatedRecipient,\\n bytes updatedMessage,\\n bytes depositorSignature\\n );\\n\\n event FilledV3Relay(\\n address inputToken,\\n address outputToken,\\n uint256 inputAmount,\\n uint256 outputAmount,\\n uint256 repaymentChainId,\\n uint256 indexed originChainId,\\n uint32 indexed depositId,\\n uint32 fillDeadline,\\n uint32 exclusivityDeadline,\\n address exclusiveRelayer,\\n address indexed relayer,\\n address depositor,\\n address recipient,\\n bytes message,\\n V3RelayExecutionEventInfo relayExecutionInfo\\n );\\n\\n event RequestedV3SlowFill(\\n address inputToken,\\n address outputToken,\\n uint256 inputAmount,\\n uint256 outputAmount,\\n uint256 indexed originChainId,\\n uint32 indexed depositId,\\n uint32 fillDeadline,\\n uint32 exclusivityDeadline,\\n address exclusiveRelayer,\\n address depositor,\\n address recipient,\\n bytes message\\n );\\n\\n /**************************************\\n * FUNCTIONS *\\n **************************************/\\n\\n function depositV3(\\n address depositor,\\n address recipient,\\n address inputToken,\\n address outputToken,\\n uint256 inputAmount,\\n uint256 outputAmount,\\n uint256 destinationChainId,\\n address exclusiveRelayer,\\n uint32 quoteTimestamp,\\n uint32 fillDeadline,\\n uint32 exclusivityDeadline,\\n bytes calldata message\\n ) external payable;\\n\\n function depositV3Now(\\n address depositor,\\n address recipient,\\n address inputToken,\\n address outputToken,\\n uint256 inputAmount,\\n uint256 outputAmount,\\n uint256 destinationChainId,\\n address exclusiveRelayer,\\n uint32 fillDeadlineOffset,\\n uint32 exclusivityDeadline,\\n bytes calldata message\\n ) external payable;\\n\\n function speedUpV3Deposit(\\n address depositor,\\n uint32 depositId,\\n uint256 updatedOutputAmount,\\n address updatedRecipient,\\n bytes calldata updatedMessage,\\n bytes calldata depositorSignature\\n ) external;\\n\\n function fillV3Relay(V3RelayData calldata relayData, uint256 repaymentChainId) external;\\n\\n function fillV3RelayWithUpdatedDeposit(\\n V3RelayData calldata relayData,\\n uint256 repaymentChainId,\\n uint256 updatedOutputAmount,\\n address updatedRecipient,\\n bytes calldata updatedMessage,\\n bytes calldata depositorSignature\\n ) external;\\n\\n function requestV3SlowFill(V3RelayData calldata relayData) external;\\n\\n function executeV3SlowRelayLeaf(\\n V3SlowFill calldata slowFillLeaf,\\n uint32 rootBundleId,\\n bytes32[] calldata proof\\n ) external;\\n\\n /**************************************\\n * ERRORS *\\n **************************************/\\n\\n error DisabledRoute();\\n error InvalidQuoteTimestamp();\\n error InvalidFillDeadline();\\n error InvalidExclusiveRelayer();\\n error InvalidExclusivityDeadline();\\n error MsgValueDoesNotMatchInputAmount();\\n error NotExclusiveRelayer();\\n error NoSlowFillsInExclusivityWindow();\\n error RelayFilled();\\n error InvalidSlowFillRequest();\\n error ExpiredFillDeadline();\\n error InvalidMerkleProof();\\n error InvalidChainId();\\n error InvalidMerkleLeaf();\\n error ClaimedMerkleLeaf();\\n error InvalidPayoutAdjustmentPct();\\n}\\n\",\"keccak256\":\"0x374b7e9cb8afbcaec69cdbcde480676b5d927db84c7f38221331d1226af68d9d\",\"license\":\"BUSL-1.1\"}},\"version\":1}", + "bytecode": "0x60808060405234610016576103a4908161001c8239f35b600080fdfe600436101561000d57600080fd5b6000803560e01c63902e949c1461002357600080fd5b6101607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261036b5773ffffffffffffffffffffffffffffffffffffffff6004358181168103610367576024359082821682036103635760443591838316830361035f5760c435848116810361035b5760e4359063ffffffff928383168303610357576101043590848216820361035357610124359385851685036103225767ffffffffffffffff610144351161032257366023610144350112156103225767ffffffffffffffff6101443560040135116103265767ffffffffffffffff6004610144350135601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f0116608090810191821191101761032657608060046101443590810135601f81017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f011683016040529182905236910160240111610322576101443560048101359060240160a03760a06004610144350135018a90526064353403610322578887163b15610322578887163b1561032257918589979593888296818e9c60409e9b979e519e8f9d8e917f7b9392320000000000000000000000000000000000000000000000000000000083523360048401521690602401521660448c01528b60648c015260643560848c015260843560a48c015260a43560c48c01521660e48a01521661010488015216610124860152166101448401526101648301610180905260805180610184850152845b8181106103075750908391827fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f6101a49389858286010152011681010301923491165af180156102fc576102ba575080f35b67ffffffffffffffff81116102cf5760405280f35b6024827f4e487b710000000000000000000000000000000000000000000000000000000081526041600452fd5b6040513d84823e3d90fd5b60a08101518782016101a40152879550869450602001610266565b8980fd5b60248a7f4e487b710000000000000000000000000000000000000000000000000000000081526041600452fd5b8880fd5b8780fd5b8580fd5b8480fd5b8380fd5b8280fd5b80fdfea26469706673582212201ceff237e6adbd0d3f92e892f7f3f51306c23eac5f7e3f896c2c723d9e5be3a664736f6c63430008130033", + "deployedBytecode": "0x600436101561000d57600080fd5b6000803560e01c63902e949c1461002357600080fd5b6101607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261036b5773ffffffffffffffffffffffffffffffffffffffff6004358181168103610367576024359082821682036103635760443591838316830361035f5760c435848116810361035b5760e4359063ffffffff928383168303610357576101043590848216820361035357610124359385851685036103225767ffffffffffffffff610144351161032257366023610144350112156103225767ffffffffffffffff6101443560040135116103265767ffffffffffffffff6004610144350135601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f0116608090810191821191101761032657608060046101443590810135601f81017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f011683016040529182905236910160240111610322576101443560048101359060240160a03760a06004610144350135018a90526064353403610322578887163b15610322578887163b1561032257918589979593888296818e9c60409e9b979e519e8f9d8e917f7b9392320000000000000000000000000000000000000000000000000000000083523360048401521690602401521660448c01528b60648c015260643560848c015260843560a48c015260a43560c48c01521660e48a01521661010488015216610124860152166101448401526101648301610180905260805180610184850152845b8181106103075750908391827fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f6101a49389858286010152011681010301923491165af180156102fc576102ba575080f35b67ffffffffffffffff81116102cf5760405280f35b6024827f4e487b710000000000000000000000000000000000000000000000000000000081526041600452fd5b6040513d84823e3d90fd5b60a08101518782016101a40152879550869450602001610266565b8980fd5b60248a7f4e487b710000000000000000000000000000000000000000000000000000000081526041600452fd5b8880fd5b8780fd5b8580fd5b8480fd5b8380fd5b8280fd5b80fdfea26469706673582212201ceff237e6adbd0d3f92e892f7f3f51306c23eac5f7e3f896c2c723d9e5be3a664736f6c63430008130033", "devdoc": { + "custom:security-contact": "bugs@across.to", "details": "This contract must be deployed via Create2 to the same address on all chains. That way, an errant transaction sent to the wrong chain will be blocked by this contract rather than hitting a dead address. This means that this contract will not work to protect chains, like zkSync, where Create2 address derivations don't match other chains. Source: https://era.zksync.io/docs/reference/architecture/differences-with-ethereum.html#create-create2", "kind": "dev", "methods": { - "deposit(address,address,address,uint256,uint256,int64,uint32,bytes,uint256)": { + "deposit(address,address,address,uint256,uint256,uint256,address,uint32,uint32,uint32,bytes)": { "details": "Protects the caller from losing their ETH (or other native token) by reverting if the SpokePool address they intended to call does not exist on this chain. Because this contract can be deployed at the same address everywhere callers should be protected even if the transaction is submitted to an unintended network. This contract should only be used for native token deposits, as this problem only exists for native tokens.", "params": { - "amount": "Amount of tokens to deposit. Will be amount of tokens to receive less fees.", "destinationChainId": "Denotes network where user will receive funds from SpokePool by a relayer.", - "maxCount": "used to protect the depositor from frontrunning to guarantee their quote remains valid. Note: this is intended to be used to pass along instructions for how a contract should use or allocate the tokens.", + "exclusiveRelayer": "Address of the relayer who has exclusive rights to fill this deposit. Can be set to 0x0 if no exclusivity period is desired. If so, then must set exclusivityDeadline to 0.", + "exclusivityDeadline": "Timestamp after which any relayer can fill this deposit. Must set to 0 if exclusiveRelayer is set to 0x0, and vice versa.", + "fillDeadline": "Timestamp after which this deposit can no longer be filled.", + "inputAmount": "Amount of tokens to deposit.", + "inputToken": "Token to lock into this contract to initiate deposit.", "message": "Arbitrary data that can be used to pass additional information to the recipient along with the tokens. Note: this is intended to be used to pass along instructions for how a contract should use or allocate the tokens.", - "originToken": "Token to lock into this contract to initiate deposit.", + "outputAmount": "Amount of tokens to receive on destination chain.", "quoteTimestamp": "Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid to LP pool on HubPool.", "recipient": "Address to receive funds at on destination chain.", - "relayerFeePct": "% of deposit amount taken out to incentivize a fast relayer.", "spokePool": "Address of the SpokePool contract that the user is intending to call." } } @@ -101,7 +114,7 @@ "userdoc": { "kind": "user", "methods": { - "deposit(address,address,address,uint256,uint256,int64,uint32,bytes,uint256)": { + "deposit(address,address,address,uint256,uint256,uint256,address,uint32,uint32,uint32,bytes)": { "notice": "Passthrough function to `depositV3()` on the SpokePool contract." } }, diff --git a/deployments/mode/solcInputs/1a67233dfe969c05446730f26ab1d2c8.json b/deployments/mode/solcInputs/1a67233dfe969c05446730f26ab1d2c8.json new file mode 100644 index 000000000..96daeb1aa --- /dev/null +++ b/deployments/mode/solcInputs/1a67233dfe969c05446730f26ab1d2c8.json @@ -0,0 +1,43 @@ +{ + "language": "Solidity", + "sources": { + "@openzeppelin/contracts/utils/Address.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (utils/Address.sol)\n\npragma solidity ^0.8.1;\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 * Furthermore, `isContract` will also return true if the target contract within\n * the same transaction is already scheduled for destruction by `SELFDESTRUCT`,\n * which only has an effect at the end of a transaction.\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 > 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://consensys.net/diligence/blog/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.8.0/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n require(address(this).balance >= amount, \"Address: insufficient balance\");\n\n (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 functionCallWithValue(target, data, 0, \"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(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n return functionCallWithValue(target, data, value, \"Address: low-level call with value failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\n * with `errorMessage` as a fallback revert reason when `target` reverts.\n *\n * _Available since v3.1._\n */\n function functionCallWithValue(\n address target,\n bytes memory data,\n uint256 value,\n string memory errorMessage\n ) internal returns (bytes memory) {\n require(address(this).balance >= value, \"Address: insufficient balance for call\");\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, 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 (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, 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 (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata, errorMessage);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling\n * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.\n *\n * _Available since v4.8._\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata,\n string memory errorMessage\n ) internal view returns (bytes memory) {\n if (success) {\n if (returndata.length == 0) {\n // only check isContract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n require(isContract(target), \"Address: call to non-contract\");\n }\n return returndata;\n } else {\n _revert(returndata, errorMessage);\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the\n * revert reason or 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 _revert(returndata, errorMessage);\n }\n }\n\n function _revert(bytes memory returndata, string memory errorMessage) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length > 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert(errorMessage);\n }\n }\n}\n" + }, + "contracts/interfaces/V3SpokePoolInterface.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n// Contains structs and functions used by SpokePool contracts to facilitate universal settlement.\ninterface V3SpokePoolInterface {\n /**************************************\n * ENUMS *\n **************************************/\n\n // Fill status tracks on-chain state of deposit, uniquely identified by relayHash.\n enum FillStatus {\n Unfilled,\n RequestedSlowFill,\n Filled\n }\n // Fill type is emitted in the FilledRelay event to assist Dataworker with determining which types of\n // fills to refund (e.g. only fast fills) and whether a fast fill created a sow fill excess.\n enum FillType {\n FastFill,\n // Fast fills are normal fills that do not replace a slow fill request.\n ReplacedSlowFill,\n // Replaced slow fills are fast fills that replace a slow fill request. This type is used by the Dataworker\n // to know when to send excess funds from the SpokePool to the HubPool because they can no longer be used\n // for a slow fill execution.\n SlowFill\n // Slow fills are requested via requestSlowFill and executed by executeSlowRelayLeaf after a bundle containing\n // the slow fill is validated.\n }\n\n /**************************************\n * STRUCTS *\n **************************************/\n\n // This struct represents the data to fully specify a **unique** relay submitted on this chain.\n // This data is hashed with the chainId() and saved by the SpokePool to prevent collisions and protect against\n // replay attacks on other chains. If any portion of this data differs, the relay is considered to be\n // completely distinct.\n struct V3RelayData {\n // The address that made the deposit on the origin chain.\n address depositor;\n // The recipient address on the destination chain.\n address recipient;\n // This is the exclusive relayer who can fill the deposit before the exclusivity deadline.\n address exclusiveRelayer;\n // Token that is deposited on origin chain by depositor.\n address inputToken;\n // Token that is received on destination chain by recipient.\n address outputToken;\n // The amount of input token deposited by depositor.\n uint256 inputAmount;\n // The amount of output token to be received by recipient.\n uint256 outputAmount;\n // Origin chain id.\n uint256 originChainId;\n // The id uniquely identifying this deposit on the origin chain.\n uint32 depositId;\n // The timestamp on the destination chain after which this deposit can no longer be filled.\n uint32 fillDeadline;\n // The timestamp on the destination chain after which any relayer can fill the deposit.\n uint32 exclusivityDeadline;\n // Data that is forwarded to the recipient.\n bytes message;\n }\n\n // Contains parameters passed in by someone who wants to execute a slow relay leaf.\n struct V3SlowFill {\n V3RelayData relayData;\n uint256 chainId;\n uint256 updatedOutputAmount;\n }\n\n // Contains information about a relay to be sent along with additional information that is not unique to the\n // relay itself but is required to know how to process the relay. For example, \"updatedX\" fields can be used\n // by the relayer to modify fields of the relay with the depositor's permission, and \"repaymentChainId\" is specified\n // by the relayer to determine where to take a relayer refund, but doesn't affect the uniqueness of the relay.\n struct V3RelayExecutionParams {\n V3RelayData relay;\n bytes32 relayHash;\n uint256 updatedOutputAmount;\n address updatedRecipient;\n bytes updatedMessage;\n uint256 repaymentChainId;\n }\n\n // Packs together parameters emitted in FilledV3Relay because there are too many emitted otherwise.\n // Similar to V3RelayExecutionParams, these parameters are not used to uniquely identify the deposit being\n // filled so they don't have to be unpacked by all clients.\n struct V3RelayExecutionEventInfo {\n address updatedRecipient;\n bytes updatedMessage;\n uint256 updatedOutputAmount;\n FillType fillType;\n }\n\n /**************************************\n * EVENTS *\n **************************************/\n\n event V3FundsDeposited(\n address inputToken,\n address outputToken,\n uint256 inputAmount,\n uint256 outputAmount,\n uint256 indexed destinationChainId,\n uint32 indexed depositId,\n uint32 quoteTimestamp,\n uint32 fillDeadline,\n uint32 exclusivityDeadline,\n address indexed depositor,\n address recipient,\n address exclusiveRelayer,\n bytes message\n );\n\n event RequestedSpeedUpV3Deposit(\n uint256 updatedOutputAmount,\n uint32 indexed depositId,\n address indexed depositor,\n address updatedRecipient,\n bytes updatedMessage,\n bytes depositorSignature\n );\n\n event FilledV3Relay(\n address inputToken,\n address outputToken,\n uint256 inputAmount,\n uint256 outputAmount,\n uint256 repaymentChainId,\n uint256 indexed originChainId,\n uint32 indexed depositId,\n uint32 fillDeadline,\n uint32 exclusivityDeadline,\n address exclusiveRelayer,\n address indexed relayer,\n address depositor,\n address recipient,\n bytes message,\n V3RelayExecutionEventInfo relayExecutionInfo\n );\n\n event RequestedV3SlowFill(\n address inputToken,\n address outputToken,\n uint256 inputAmount,\n uint256 outputAmount,\n uint256 indexed originChainId,\n uint32 indexed depositId,\n uint32 fillDeadline,\n uint32 exclusivityDeadline,\n address exclusiveRelayer,\n address depositor,\n address recipient,\n bytes message\n );\n\n /**************************************\n * FUNCTIONS *\n **************************************/\n\n function depositV3(\n address depositor,\n address recipient,\n address inputToken,\n address outputToken,\n uint256 inputAmount,\n uint256 outputAmount,\n uint256 destinationChainId,\n address exclusiveRelayer,\n uint32 quoteTimestamp,\n uint32 fillDeadline,\n uint32 exclusivityDeadline,\n bytes calldata message\n ) external payable;\n\n function depositV3Now(\n address depositor,\n address recipient,\n address inputToken,\n address outputToken,\n uint256 inputAmount,\n uint256 outputAmount,\n uint256 destinationChainId,\n address exclusiveRelayer,\n uint32 fillDeadlineOffset,\n uint32 exclusivityDeadline,\n bytes calldata message\n ) external payable;\n\n function speedUpV3Deposit(\n address depositor,\n uint32 depositId,\n uint256 updatedOutputAmount,\n address updatedRecipient,\n bytes calldata updatedMessage,\n bytes calldata depositorSignature\n ) external;\n\n function fillV3Relay(V3RelayData calldata relayData, uint256 repaymentChainId) external;\n\n function fillV3RelayWithUpdatedDeposit(\n V3RelayData calldata relayData,\n uint256 repaymentChainId,\n uint256 updatedOutputAmount,\n address updatedRecipient,\n bytes calldata updatedMessage,\n bytes calldata depositorSignature\n ) external;\n\n function requestV3SlowFill(V3RelayData calldata relayData) external;\n\n function executeV3SlowRelayLeaf(\n V3SlowFill calldata slowFillLeaf,\n uint32 rootBundleId,\n bytes32[] calldata proof\n ) external;\n\n /**************************************\n * ERRORS *\n **************************************/\n\n error DisabledRoute();\n error InvalidQuoteTimestamp();\n error InvalidFillDeadline();\n error InvalidExclusiveRelayer();\n error InvalidExclusivityDeadline();\n error MsgValueDoesNotMatchInputAmount();\n error NotExclusiveRelayer();\n error NoSlowFillsInExclusivityWindow();\n error RelayFilled();\n error InvalidSlowFillRequest();\n error ExpiredFillDeadline();\n error InvalidMerkleProof();\n error InvalidChainId();\n error InvalidMerkleLeaf();\n error ClaimedMerkleLeaf();\n error InvalidPayoutAdjustmentPct();\n}\n" + }, + "contracts/SpokePoolVerifier.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/utils/Address.sol\";\nimport \"./interfaces/V3SpokePoolInterface.sol\";\n\n/**\n * @notice SpokePoolVerifier is a contract that verifies that the SpokePool exists on this chain before sending ETH to it.\n * @dev This contract must be deployed via Create2 to the same address on all chains. That way, an errant transaction sent\n * to the wrong chain will be blocked by this contract rather than hitting a dead address. This means that this contract\n * will not work to protect chains, like zkSync, where Create2 address derivations don't match other chains.\n * Source: https://era.zksync.io/docs/reference/architecture/differences-with-ethereum.html#create-create2\n * @custom:security-contact bugs@across.to\n */\ncontract SpokePoolVerifier {\n using Address for address;\n\n /**\n * @notice Passthrough function to `depositV3()` on the SpokePool contract.\n * @dev Protects the caller from losing their ETH (or other native token) by reverting if the SpokePool address\n * they intended to call does not exist on this chain. Because this contract can be deployed at the same address\n * everywhere callers should be protected even if the transaction is submitted to an unintended network.\n * This contract should only be used for native token deposits, as this problem only exists for native tokens.\n * @param spokePool Address of the SpokePool contract that the user is intending to call.\n * @param recipient Address to receive funds at on destination chain.\n * @param inputToken Token to lock into this contract to initiate deposit.\n * @param inputAmount Amount of tokens to deposit.\n * @param outputAmount Amount of tokens to receive on destination chain.\n * @param destinationChainId Denotes network where user will receive funds from SpokePool by a relayer.\n * @param quoteTimestamp Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid\n * to LP pool on HubPool.\n * @param message Arbitrary data that can be used to pass additional information to the recipient along with the tokens.\n * Note: this is intended to be used to pass along instructions for how a contract should use or allocate the tokens.\n * @param exclusiveRelayer Address of the relayer who has exclusive rights to fill this deposit. Can be set to\n * 0x0 if no exclusivity period is desired. If so, then must set exclusivityDeadline to 0.\n * @param exclusivityDeadline Timestamp after which any relayer can fill this deposit. Must set\n * to 0 if exclusiveRelayer is set to 0x0, and vice versa.\n * @param fillDeadline Timestamp after which this deposit can no longer be filled.\n */\n function deposit(\n V3SpokePoolInterface spokePool,\n address recipient,\n address inputToken,\n uint256 inputAmount,\n uint256 outputAmount,\n uint256 destinationChainId,\n uint32 quoteTimestamp,\n bytes memory message,\n address exclusiveRelayer,\n uint32 exclusivityDeadline,\n uint32 fillDeadline\n ) external payable {\n require(msg.value == inputAmount, \"msg.value != amount\");\n require(address(spokePool).isContract(), \"spokePool is not a contract\");\n // Set msg.sender as the depositor so that msg.sender can speed up the deposit.\n spokePool.depositV3{ value: msg.value }(\n msg.sender,\n recipient,\n inputToken,\n // @dev Setting outputToken to 0x0 to instruct fillers to use the equivalent token\n // as the originToken on the destination chain.\n address(0),\n inputAmount,\n outputAmount,\n destinationChainId,\n exclusiveRelayer,\n quoteTimestamp,\n fillDeadline,\n exclusivityDeadline,\n message\n );\n }\n}\n" + } + }, + "settings": { + "optimizer": { + "enabled": true, + "runs": 1000000 + }, + "viaIR": true, + "debug": { + "revertStrings": "strip" + }, + "outputSelection": { + "*": { + "*": [ + "abi", + "evm.bytecode", + "evm.deployedBytecode", + "evm.methodIdentifiers", + "metadata", + "devdoc", + "userdoc", + "storageLayout", + "evm.gasEstimates" + ], + "": ["ast"] + } + }, + "metadata": { + "useLiteralContent": true + } + } +} diff --git a/deployments/mode/solcInputs/783274f805324492b21545b62eb0dbfe.json b/deployments/mode/solcInputs/783274f805324492b21545b62eb0dbfe.json new file mode 100644 index 000000000..4bcffc07b --- /dev/null +++ b/deployments/mode/solcInputs/783274f805324492b21545b62eb0dbfe.json @@ -0,0 +1,43 @@ +{ + "language": "Solidity", + "sources": { + "@openzeppelin/contracts/utils/Address.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (utils/Address.sol)\n\npragma solidity ^0.8.1;\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 * Furthermore, `isContract` will also return true if the target contract within\n * the same transaction is already scheduled for destruction by `SELFDESTRUCT`,\n * which only has an effect at the end of a transaction.\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 > 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://consensys.net/diligence/blog/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.8.0/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n require(address(this).balance >= amount, \"Address: insufficient balance\");\n\n (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 functionCallWithValue(target, data, 0, \"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(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n return functionCallWithValue(target, data, value, \"Address: low-level call with value failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\n * with `errorMessage` as a fallback revert reason when `target` reverts.\n *\n * _Available since v3.1._\n */\n function functionCallWithValue(\n address target,\n bytes memory data,\n uint256 value,\n string memory errorMessage\n ) internal returns (bytes memory) {\n require(address(this).balance >= value, \"Address: insufficient balance for call\");\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, 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 (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, 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 (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata, errorMessage);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling\n * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.\n *\n * _Available since v4.8._\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata,\n string memory errorMessage\n ) internal view returns (bytes memory) {\n if (success) {\n if (returndata.length == 0) {\n // only check isContract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n require(isContract(target), \"Address: call to non-contract\");\n }\n return returndata;\n } else {\n _revert(returndata, errorMessage);\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the\n * revert reason or 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 _revert(returndata, errorMessage);\n }\n }\n\n function _revert(bytes memory returndata, string memory errorMessage) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length > 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert(errorMessage);\n }\n }\n}\n" + }, + "contracts/interfaces/V3SpokePoolInterface.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n// Contains structs and functions used by SpokePool contracts to facilitate universal settlement.\ninterface V3SpokePoolInterface {\n /**************************************\n * ENUMS *\n **************************************/\n\n // Fill status tracks on-chain state of deposit, uniquely identified by relayHash.\n enum FillStatus {\n Unfilled,\n RequestedSlowFill,\n Filled\n }\n // Fill type is emitted in the FilledRelay event to assist Dataworker with determining which types of\n // fills to refund (e.g. only fast fills) and whether a fast fill created a sow fill excess.\n enum FillType {\n FastFill,\n // Fast fills are normal fills that do not replace a slow fill request.\n ReplacedSlowFill,\n // Replaced slow fills are fast fills that replace a slow fill request. This type is used by the Dataworker\n // to know when to send excess funds from the SpokePool to the HubPool because they can no longer be used\n // for a slow fill execution.\n SlowFill\n // Slow fills are requested via requestSlowFill and executed by executeSlowRelayLeaf after a bundle containing\n // the slow fill is validated.\n }\n\n /**************************************\n * STRUCTS *\n **************************************/\n\n // This struct represents the data to fully specify a **unique** relay submitted on this chain.\n // This data is hashed with the chainId() and saved by the SpokePool to prevent collisions and protect against\n // replay attacks on other chains. If any portion of this data differs, the relay is considered to be\n // completely distinct.\n struct V3RelayData {\n // The address that made the deposit on the origin chain.\n address depositor;\n // The recipient address on the destination chain.\n address recipient;\n // This is the exclusive relayer who can fill the deposit before the exclusivity deadline.\n address exclusiveRelayer;\n // Token that is deposited on origin chain by depositor.\n address inputToken;\n // Token that is received on destination chain by recipient.\n address outputToken;\n // The amount of input token deposited by depositor.\n uint256 inputAmount;\n // The amount of output token to be received by recipient.\n uint256 outputAmount;\n // Origin chain id.\n uint256 originChainId;\n // The id uniquely identifying this deposit on the origin chain.\n uint32 depositId;\n // The timestamp on the destination chain after which this deposit can no longer be filled.\n uint32 fillDeadline;\n // The timestamp on the destination chain after which any relayer can fill the deposit.\n uint32 exclusivityDeadline;\n // Data that is forwarded to the recipient.\n bytes message;\n }\n\n // Contains parameters passed in by someone who wants to execute a slow relay leaf.\n struct V3SlowFill {\n V3RelayData relayData;\n uint256 chainId;\n uint256 updatedOutputAmount;\n }\n\n // Contains information about a relay to be sent along with additional information that is not unique to the\n // relay itself but is required to know how to process the relay. For example, \"updatedX\" fields can be used\n // by the relayer to modify fields of the relay with the depositor's permission, and \"repaymentChainId\" is specified\n // by the relayer to determine where to take a relayer refund, but doesn't affect the uniqueness of the relay.\n struct V3RelayExecutionParams {\n V3RelayData relay;\n bytes32 relayHash;\n uint256 updatedOutputAmount;\n address updatedRecipient;\n bytes updatedMessage;\n uint256 repaymentChainId;\n }\n\n // Packs together parameters emitted in FilledV3Relay because there are too many emitted otherwise.\n // Similar to V3RelayExecutionParams, these parameters are not used to uniquely identify the deposit being\n // filled so they don't have to be unpacked by all clients.\n struct V3RelayExecutionEventInfo {\n address updatedRecipient;\n bytes updatedMessage;\n uint256 updatedOutputAmount;\n FillType fillType;\n }\n\n /**************************************\n * EVENTS *\n **************************************/\n\n event V3FundsDeposited(\n address inputToken,\n address outputToken,\n uint256 inputAmount,\n uint256 outputAmount,\n uint256 indexed destinationChainId,\n uint32 indexed depositId,\n uint32 quoteTimestamp,\n uint32 fillDeadline,\n uint32 exclusivityDeadline,\n address indexed depositor,\n address recipient,\n address exclusiveRelayer,\n bytes message\n );\n\n event RequestedSpeedUpV3Deposit(\n uint256 updatedOutputAmount,\n uint32 indexed depositId,\n address indexed depositor,\n address updatedRecipient,\n bytes updatedMessage,\n bytes depositorSignature\n );\n\n event FilledV3Relay(\n address inputToken,\n address outputToken,\n uint256 inputAmount,\n uint256 outputAmount,\n uint256 repaymentChainId,\n uint256 indexed originChainId,\n uint32 indexed depositId,\n uint32 fillDeadline,\n uint32 exclusivityDeadline,\n address exclusiveRelayer,\n address indexed relayer,\n address depositor,\n address recipient,\n bytes message,\n V3RelayExecutionEventInfo relayExecutionInfo\n );\n\n event RequestedV3SlowFill(\n address inputToken,\n address outputToken,\n uint256 inputAmount,\n uint256 outputAmount,\n uint256 indexed originChainId,\n uint32 indexed depositId,\n uint32 fillDeadline,\n uint32 exclusivityDeadline,\n address exclusiveRelayer,\n address depositor,\n address recipient,\n bytes message\n );\n\n /**************************************\n * FUNCTIONS *\n **************************************/\n\n function depositV3(\n address depositor,\n address recipient,\n address inputToken,\n address outputToken,\n uint256 inputAmount,\n uint256 outputAmount,\n uint256 destinationChainId,\n address exclusiveRelayer,\n uint32 quoteTimestamp,\n uint32 fillDeadline,\n uint32 exclusivityDeadline,\n bytes calldata message\n ) external payable;\n\n function depositV3Now(\n address depositor,\n address recipient,\n address inputToken,\n address outputToken,\n uint256 inputAmount,\n uint256 outputAmount,\n uint256 destinationChainId,\n address exclusiveRelayer,\n uint32 fillDeadlineOffset,\n uint32 exclusivityDeadline,\n bytes calldata message\n ) external payable;\n\n function speedUpV3Deposit(\n address depositor,\n uint32 depositId,\n uint256 updatedOutputAmount,\n address updatedRecipient,\n bytes calldata updatedMessage,\n bytes calldata depositorSignature\n ) external;\n\n function fillV3Relay(V3RelayData calldata relayData, uint256 repaymentChainId) external;\n\n function fillV3RelayWithUpdatedDeposit(\n V3RelayData calldata relayData,\n uint256 repaymentChainId,\n uint256 updatedOutputAmount,\n address updatedRecipient,\n bytes calldata updatedMessage,\n bytes calldata depositorSignature\n ) external;\n\n function requestV3SlowFill(V3RelayData calldata relayData) external;\n\n function executeV3SlowRelayLeaf(\n V3SlowFill calldata slowFillLeaf,\n uint32 rootBundleId,\n bytes32[] calldata proof\n ) external;\n\n /**************************************\n * ERRORS *\n **************************************/\n\n error DisabledRoute();\n error InvalidQuoteTimestamp();\n error InvalidFillDeadline();\n error InvalidExclusiveRelayer();\n error InvalidExclusivityDeadline();\n error MsgValueDoesNotMatchInputAmount();\n error NotExclusiveRelayer();\n error NoSlowFillsInExclusivityWindow();\n error RelayFilled();\n error InvalidSlowFillRequest();\n error ExpiredFillDeadline();\n error InvalidMerkleProof();\n error InvalidChainId();\n error InvalidMerkleLeaf();\n error ClaimedMerkleLeaf();\n error InvalidPayoutAdjustmentPct();\n}\n" + }, + "contracts/SpokePoolVerifier.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/utils/Address.sol\";\nimport \"./interfaces/V3SpokePoolInterface.sol\";\n\n/**\n * @notice SpokePoolVerifier is a contract that verifies that the SpokePool exists on this chain before sending ETH to it.\n * @dev This contract must be deployed via Create2 to the same address on all chains. That way, an errant transaction sent\n * to the wrong chain will be blocked by this contract rather than hitting a dead address. This means that this contract\n * will not work to protect chains, like zkSync, where Create2 address derivations don't match other chains.\n * Source: https://era.zksync.io/docs/reference/architecture/differences-with-ethereum.html#create-create2\n * @custom:security-contact bugs@across.to\n */\ncontract SpokePoolVerifier {\n using Address for address;\n\n /**\n * @notice Passthrough function to `depositV3()` on the SpokePool contract.\n * @dev Protects the caller from losing their ETH (or other native token) by reverting if the SpokePool address\n * they intended to call does not exist on this chain. Because this contract can be deployed at the same address\n * everywhere callers should be protected even if the transaction is submitted to an unintended network.\n * This contract should only be used for native token deposits, as this problem only exists for native tokens.\n * @param spokePool Address of the SpokePool contract that the user is intending to call.\n * @param recipient Address to receive funds at on destination chain.\n * @param inputToken Token to lock into this contract to initiate deposit.\n * @param inputAmount Amount of tokens to deposit.\n * @param outputAmount Amount of tokens to receive on destination chain.\n * @param destinationChainId Denotes network where user will receive funds from SpokePool by a relayer.\n * @param quoteTimestamp Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid\n * to LP pool on HubPool.\n * @param message Arbitrary data that can be used to pass additional information to the recipient along with the tokens.\n * Note: this is intended to be used to pass along instructions for how a contract should use or allocate the tokens.\n * @param exclusiveRelayer Address of the relayer who has exclusive rights to fill this deposit. Can be set to\n * 0x0 if no exclusivity period is desired. If so, then must set exclusivityDeadline to 0.\n * @param exclusivityDeadline Timestamp after which any relayer can fill this deposit. Must set\n * to 0 if exclusiveRelayer is set to 0x0, and vice versa.\n * @param fillDeadline Timestamp after which this deposit can no longer be filled.\n */\n function deposit(\n V3SpokePoolInterface spokePool,\n address recipient,\n address inputToken,\n uint256 inputAmount,\n uint256 outputAmount,\n uint256 destinationChainId,\n address exclusiveRelayer,\n uint32 quoteTimestamp,\n uint32 fillDeadline,\n uint32 exclusivityDeadline,\n bytes memory message\n ) external payable {\n require(msg.value == inputAmount, \"msg.value != amount\");\n require(address(spokePool).isContract(), \"spokePool is not a contract\");\n // Set msg.sender as the depositor so that msg.sender can speed up the deposit.\n spokePool.depositV3{ value: msg.value }(\n msg.sender,\n recipient,\n inputToken,\n // @dev Setting outputToken to 0x0 to instruct fillers to use the equivalent token\n // as the originToken on the destination chain.\n address(0),\n inputAmount,\n outputAmount,\n destinationChainId,\n exclusiveRelayer,\n quoteTimestamp,\n fillDeadline,\n exclusivityDeadline,\n message\n );\n }\n}\n" + } + }, + "settings": { + "optimizer": { + "enabled": true, + "runs": 1000000 + }, + "viaIR": true, + "debug": { + "revertStrings": "strip" + }, + "outputSelection": { + "*": { + "*": [ + "abi", + "evm.bytecode", + "evm.deployedBytecode", + "evm.methodIdentifiers", + "metadata", + "devdoc", + "userdoc", + "storageLayout", + "evm.gasEstimates" + ], + "": ["ast"] + } + }, + "metadata": { + "useLiteralContent": true + } + } +} diff --git a/deployments/optimism/SpokePoolVerifier.json b/deployments/optimism/SpokePoolVerifier.json index b254656bc..b0daf50e4 100644 --- a/deployments/optimism/SpokePoolVerifier.json +++ b/deployments/optimism/SpokePoolVerifier.json @@ -1,10 +1,10 @@ { - "address": "0xB4A8d45647445EA9FC3E1058096142390683dBC2", + "address": "0x4437A1Ee2dFb72954F21A44C3F0F0E2CBA5A5C27", "abi": [ { "inputs": [ { - "internalType": "contract SpokePoolInterface", + "internalType": "contract V3SpokePoolInterface", "name": "spokePool", "type": "address" }, @@ -15,12 +15,17 @@ }, { "internalType": "address", - "name": "originToken", + "name": "inputToken", "type": "address" }, { "internalType": "uint256", - "name": "amount", + "name": "inputAmount", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "outputAmount", "type": "uint256" }, { @@ -29,24 +34,29 @@ "type": "uint256" }, { - "internalType": "int64", - "name": "relayerFeePct", - "type": "int64" + "internalType": "address", + "name": "exclusiveRelayer", + "type": "address" }, { "internalType": "uint32", "name": "quoteTimestamp", "type": "uint32" }, + { + "internalType": "uint32", + "name": "fillDeadline", + "type": "uint32" + }, + { + "internalType": "uint32", + "name": "exclusivityDeadline", + "type": "uint32" + }, { "internalType": "bytes", "name": "message", "type": "bytes" - }, - { - "internalType": "uint256", - "name": "maxCount", - "type": "uint256" } ], "name": "deposit", @@ -55,43 +65,46 @@ "type": "function" } ], - "transactionHash": "0x7eda4d12037023796fbd04e342a6a26f17edc418f7e324e247f68100509e5043", + "transactionHash": "0xdcf4918843954350c7418091dbdd87e137289e6789d87d0c04310efff60203fd", "receipt": { "to": "0x4e59b44847b379578588920cA78FbF26c0B4956C", "from": "0x9A8f92a830A5cB89a3816e3D267CB7791c16b04D", "contractAddress": null, - "transactionIndex": 11, - "gasUsed": "234906", + "transactionIndex": 10, + "gasUsed": "254525", "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - "blockHash": "0x9bb8440685d3b74b6aa21949c291d2ed38bdf1da82d22d0ca7ccbdd05d41317b", - "transactionHash": "0x7eda4d12037023796fbd04e342a6a26f17edc418f7e324e247f68100509e5043", + "blockHash": "0x5a2f4ab1d156f879d67f89780f8786f0ca01f579cd7998d072e015243dd5327b", + "transactionHash": "0xdcf4918843954350c7418091dbdd87e137289e6789d87d0c04310efff60203fd", "logs": [], - "blockNumber": 117881120, - "cumulativeGasUsed": "3450371", + "blockNumber": 123208362, + "cumulativeGasUsed": "2562897", "status": 1, "byzantium": true }, "args": [], - "numDeployments": 3, - "solcInputHash": "53ab13385da43753d9a657e7780a0560", - "metadata": "{\"compiler\":{\"version\":\"0.8.19+commit.7dd6d404\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"contract SpokePoolInterface\",\"name\":\"spokePool\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"internalType\":\"int64\",\"name\":\"relayerFeePct\",\"type\":\"int64\"},{\"internalType\":\"uint32\",\"name\":\"quoteTimestamp\",\"type\":\"uint32\"},{\"internalType\":\"bytes\",\"name\":\"message\",\"type\":\"bytes\"},{\"internalType\":\"uint256\",\"name\":\"maxCount\",\"type\":\"uint256\"}],\"name\":\"deposit\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"This contract must be deployed via Create2 to the same address on all chains. That way, an errant transaction sent to the wrong chain will be blocked by this contract rather than hitting a dead address. This means that this contract will not work to protect chains, like zkSync, where Create2 address derivations don't match other chains. Source: https://era.zksync.io/docs/reference/architecture/differences-with-ethereum.html#create-create2\",\"kind\":\"dev\",\"methods\":{\"deposit(address,address,address,uint256,uint256,int64,uint32,bytes,uint256)\":{\"details\":\"Protects the caller from losing their ETH (or other native token) by reverting if the SpokePool address they intended to call does not exist on this chain. Because this contract can be deployed at the same address everywhere callers should be protected even if the transaction is submitted to an unintended network. This contract should only be used for native token deposits, as this problem only exists for native tokens.\",\"params\":{\"amount\":\"Amount of tokens to deposit. Will be amount of tokens to receive less fees.\",\"destinationChainId\":\"Denotes network where user will receive funds from SpokePool by a relayer.\",\"maxCount\":\"used to protect the depositor from frontrunning to guarantee their quote remains valid. Note: this is intended to be used to pass along instructions for how a contract should use or allocate the tokens.\",\"message\":\"Arbitrary data that can be used to pass additional information to the recipient along with the tokens. Note: this is intended to be used to pass along instructions for how a contract should use or allocate the tokens.\",\"originToken\":\"Token to lock into this contract to initiate deposit.\",\"quoteTimestamp\":\"Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid to LP pool on HubPool.\",\"recipient\":\"Address to receive funds at on destination chain.\",\"relayerFeePct\":\"% of deposit amount taken out to incentivize a fast relayer.\",\"spokePool\":\"Address of the SpokePool contract that the user is intending to call.\"}}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"deposit(address,address,address,uint256,uint256,int64,uint32,bytes,uint256)\":{\"notice\":\"Passthrough function to `depositV3()` on the SpokePool contract.\"}},\"notice\":\"SpokePoolVerifier is a contract that verifies that the SpokePool exists on this chain before sending ETH to it.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/SpokePoolVerifier.sol\":\"SpokePoolVerifier\"},\"debug\":{\"revertStrings\":\"strip\"},\"evmVersion\":\"paris\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":1000000},\"remappings\":[],\"viaIR\":true},\"sources\":{\"@openzeppelin/contracts/utils/Address.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.9.0) (utils/Address.sol)\\n\\npragma solidity ^0.8.1;\\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 * Furthermore, `isContract` will also return true if the target contract within\\n * the same transaction is already scheduled for destruction by `SELFDESTRUCT`,\\n * which only has an effect at the end of a transaction.\\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 > 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://consensys.net/diligence/blog/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.8.0/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\\n */\\n function sendValue(address payable recipient, uint256 amount) internal {\\n require(address(this).balance >= amount, \\\"Address: insufficient balance\\\");\\n\\n (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 functionCallWithValue(target, data, 0, \\\"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(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, value, \\\"Address: low-level call with value failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\\n * with `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(address(this).balance >= value, \\\"Address: insufficient balance for call\\\");\\n (bool success, bytes memory returndata) = target.call{value: value}(data);\\n return verifyCallResultFromTarget(target, 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 (bool success, bytes memory returndata) = target.staticcall(data);\\n return verifyCallResultFromTarget(target, 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 (bool success, bytes memory returndata) = target.delegatecall(data);\\n return verifyCallResultFromTarget(target, success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling\\n * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.\\n *\\n * _Available since v4.8._\\n */\\n function verifyCallResultFromTarget(\\n address target,\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n if (success) {\\n if (returndata.length == 0) {\\n // only check isContract if the call was successful and the return data is empty\\n // otherwise we already know that it was a contract\\n require(isContract(target), \\\"Address: call to non-contract\\\");\\n }\\n return returndata;\\n } else {\\n _revert(returndata, errorMessage);\\n }\\n }\\n\\n /**\\n * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the\\n * revert reason or 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 _revert(returndata, errorMessage);\\n }\\n }\\n\\n function _revert(bytes memory returndata, string memory errorMessage) private pure {\\n // Look for revert reason and bubble it up if present\\n if (returndata.length > 0) {\\n // The easiest way to bubble the revert reason is using memory via assembly\\n /// @solidity memory-safe-assembly\\n assembly {\\n let returndata_size := mload(returndata)\\n revert(add(32, returndata), returndata_size)\\n }\\n } else {\\n revert(errorMessage);\\n }\\n }\\n}\\n\",\"keccak256\":\"0x006dd67219697fe68d7fbfdea512e7c4cb64a43565ed86171d67e844982da6fa\",\"license\":\"MIT\"},\"contracts/SpokePoolVerifier.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\nimport \\\"@openzeppelin/contracts/utils/Address.sol\\\";\\nimport \\\"./interfaces/SpokePoolInterface.sol\\\";\\n\\n/**\\n * @notice SpokePoolVerifier is a contract that verifies that the SpokePool exists on this chain before sending ETH to it.\\n * @dev This contract must be deployed via Create2 to the same address on all chains. That way, an errant transaction sent\\n * to the wrong chain will be blocked by this contract rather than hitting a dead address. This means that this contract\\n * will not work to protect chains, like zkSync, where Create2 address derivations don't match other chains.\\n * Source: https://era.zksync.io/docs/reference/architecture/differences-with-ethereum.html#create-create2\\n */\\ncontract SpokePoolVerifier {\\n using Address for address;\\n\\n /**\\n * @notice Passthrough function to `depositV3()` on the SpokePool contract.\\n * @dev Protects the caller from losing their ETH (or other native token) by reverting if the SpokePool address\\n * they intended to call does not exist on this chain. Because this contract can be deployed at the same address\\n * everywhere callers should be protected even if the transaction is submitted to an unintended network.\\n * This contract should only be used for native token deposits, as this problem only exists for native tokens.\\n * @param spokePool Address of the SpokePool contract that the user is intending to call.\\n * @param recipient Address to receive funds at on destination chain.\\n * @param originToken Token to lock into this contract to initiate deposit.\\n * @param amount Amount of tokens to deposit. Will be amount of tokens to receive less fees.\\n * @param destinationChainId Denotes network where user will receive funds from SpokePool by a relayer.\\n * @param relayerFeePct % of deposit amount taken out to incentivize a fast relayer.\\n * @param quoteTimestamp Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid\\n * to LP pool on HubPool.\\n * @param message Arbitrary data that can be used to pass additional information to the recipient along with the tokens.\\n * Note: this is intended to be used to pass along instructions for how a contract should use or allocate the tokens.\\n * @param maxCount used to protect the depositor from frontrunning to guarantee their quote remains valid.\\n * Note: this is intended to be used to pass along instructions for how a contract should use or allocate the tokens.\\n */\\n function deposit(\\n SpokePoolInterface spokePool,\\n address recipient,\\n address originToken,\\n uint256 amount,\\n uint256 destinationChainId,\\n int64 relayerFeePct,\\n uint32 quoteTimestamp,\\n bytes memory message,\\n uint256 maxCount\\n ) external payable {\\n require(msg.value == amount, \\\"msg.value != amount\\\");\\n require(address(spokePool).isContract(), \\\"spokePool is not a contract\\\");\\n // Set msg.sender as the depositor so that msg.sender can speed up the deposit.\\n spokePool.depositFor{ value: msg.value }(\\n msg.sender,\\n recipient,\\n originToken,\\n amount,\\n destinationChainId,\\n relayerFeePct,\\n quoteTimestamp,\\n message,\\n maxCount\\n );\\n }\\n}\\n\",\"keccak256\":\"0xfc008c31a2fde7eb0daedaa823b76931225f41ac882b6d1c515d8a38ccda60ec\",\"license\":\"BUSL-1.1\"},\"contracts/interfaces/SpokePoolInterface.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\n/**\\n * @notice Contains common data structures and functions used by all SpokePool implementations.\\n */\\ninterface SpokePoolInterface {\\n // This leaf is meant to be decoded in the SpokePool to pay out successful relayers.\\n struct RelayerRefundLeaf {\\n // This is the amount to return to the HubPool. This occurs when there is a PoolRebalanceLeaf netSendAmount that\\n // is negative. This is just the negative of this value.\\n uint256 amountToReturn;\\n // Used to verify that this is being executed on the correct destination chainId.\\n uint256 chainId;\\n // This array designates how much each of those addresses should be refunded.\\n uint256[] refundAmounts;\\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\\n uint32 leafId;\\n // The associated L2TokenAddress that these claims apply to.\\n address l2TokenAddress;\\n // Must be same length as refundAmounts and designates each address that must be refunded.\\n address[] refundAddresses;\\n }\\n\\n // Stores collection of merkle roots that can be published to this contract from the HubPool, which are referenced\\n // by \\\"data workers\\\" via inclusion proofs to execute leaves in the roots.\\n struct RootBundle {\\n // Merkle root of slow relays that were not fully filled and whose recipient is still owed funds from the LP pool.\\n bytes32 slowRelayRoot;\\n // Merkle root of relayer refunds for successful relays.\\n bytes32 relayerRefundRoot;\\n // This is a 2D bitmap tracking which leaves in the relayer refund root have been claimed, with max size of\\n // 256x(2^248) leaves per root.\\n mapping(uint256 => uint256) claimedBitmap;\\n }\\n\\n function setCrossDomainAdmin(address newCrossDomainAdmin) external;\\n\\n function setHubPool(address newHubPool) external;\\n\\n function setEnableRoute(\\n address originToken,\\n uint256 destinationChainId,\\n bool enable\\n ) external;\\n\\n function pauseDeposits(bool pause) external;\\n\\n function pauseFills(bool pause) external;\\n\\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) external;\\n\\n function emergencyDeleteRootBundle(uint256 rootBundleId) external;\\n\\n function deposit(\\n address recipient,\\n address originToken,\\n uint256 amount,\\n uint256 destinationChainId,\\n int64 relayerFeePct,\\n uint32 quoteTimestamp,\\n bytes memory message,\\n uint256 maxCount\\n ) external payable;\\n\\n function depositFor(\\n address depositor,\\n address recipient,\\n address originToken,\\n uint256 amount,\\n uint256 destinationChainId,\\n int64 relayerFeePct,\\n uint32 quoteTimestamp,\\n bytes memory message,\\n uint256 maxCount\\n ) external payable;\\n\\n function executeRelayerRefundLeaf(\\n uint32 rootBundleId,\\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\\n bytes32[] memory proof\\n ) external payable;\\n\\n function chainId() external view returns (uint256);\\n\\n error NotEOA();\\n error InvalidDepositorSignature();\\n error InvalidRelayerFeePct();\\n error MaxTransferSizeExceeded();\\n error InvalidCrossDomainAdmin();\\n error InvalidHubPool();\\n error DepositsArePaused();\\n error FillsArePaused();\\n}\\n\",\"keccak256\":\"0xc90fbd7e66e2e87e9aacbe93c20cc020cd1fc582c4fd4879807e7dc026943ea0\",\"license\":\"BUSL-1.1\"}},\"version\":1}", - "bytecode": "0x608080604052346100165761034b908161001c8239f35b600080fdfe600436101561000d57600080fd5b6000803560e01c63e0db3fcf1461002357600080fd5b610120807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103115773ffffffffffffffffffffffffffffffffffffffff600435818116810361030d576024359282841684036103095760443583811681036103055760a4358060070b81036103015760c4359063ffffffff8216820361029b5760e43567ffffffffffffffff81116102fd57366023820112156102fd57806004013567ffffffffffffffff81116102d0577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0603f81601f84011601166080016080811067ffffffffffffffff8211176102a357908a929160405280608052366024828401011161029f57602091819060240160a0376080010152606435340361029b578585163b1561029b578585163b1561029b57859694929163ffffffff91878a9896946040519a8b997f541f4f14000000000000000000000000000000000000000000000000000000008b523360048c01521660248a01521660448801526064356064880152608435608488015260070b60a48701521660c485015260e484015260805180610124850152845b8181106102805750908391827fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f6101449389858286010152610104803590850152011681010301923491165af1801561027557610233575080f35b67ffffffffffffffff81116102485760405280f35b6024827f4e487b710000000000000000000000000000000000000000000000000000000081526041600452fd5b6040513d84823e3d90fd5b60a081015187820161014401528795508694506020016101d6565b8780fd5b8280fd5b60248b7f4e487b710000000000000000000000000000000000000000000000000000000081526041600452fd5b60248a7f4e487b710000000000000000000000000000000000000000000000000000000081526041600452fd5b8880fd5b8680fd5b8580fd5b8480fd5b8380fd5b5080fdfea26469706673582212204f81f550f00970671d0755020f959a6599fd76306000e67b424172e1089b949a64736f6c63430008130033", - "deployedBytecode": "0x600436101561000d57600080fd5b6000803560e01c63e0db3fcf1461002357600080fd5b610120807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103115773ffffffffffffffffffffffffffffffffffffffff600435818116810361030d576024359282841684036103095760443583811681036103055760a4358060070b81036103015760c4359063ffffffff8216820361029b5760e43567ffffffffffffffff81116102fd57366023820112156102fd57806004013567ffffffffffffffff81116102d0577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0603f81601f84011601166080016080811067ffffffffffffffff8211176102a357908a929160405280608052366024828401011161029f57602091819060240160a0376080010152606435340361029b578585163b1561029b578585163b1561029b57859694929163ffffffff91878a9896946040519a8b997f541f4f14000000000000000000000000000000000000000000000000000000008b523360048c01521660248a01521660448801526064356064880152608435608488015260070b60a48701521660c485015260e484015260805180610124850152845b8181106102805750908391827fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f6101449389858286010152610104803590850152011681010301923491165af1801561027557610233575080f35b67ffffffffffffffff81116102485760405280f35b6024827f4e487b710000000000000000000000000000000000000000000000000000000081526041600452fd5b6040513d84823e3d90fd5b60a081015187820161014401528795508694506020016101d6565b8780fd5b8280fd5b60248b7f4e487b710000000000000000000000000000000000000000000000000000000081526041600452fd5b60248a7f4e487b710000000000000000000000000000000000000000000000000000000081526041600452fd5b8880fd5b8680fd5b8580fd5b8480fd5b8380fd5b5080fdfea26469706673582212204f81f550f00970671d0755020f959a6599fd76306000e67b424172e1089b949a64736f6c63430008130033", + "numDeployments": 5, + "solcInputHash": "783274f805324492b21545b62eb0dbfe", + "metadata": "{\"compiler\":{\"version\":\"0.8.19+commit.7dd6d404\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"contract V3SpokePoolInterface\",\"name\":\"spokePool\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"inputToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"inputAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"outputAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"exclusiveRelayer\",\"type\":\"address\"},{\"internalType\":\"uint32\",\"name\":\"quoteTimestamp\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"fillDeadline\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"exclusivityDeadline\",\"type\":\"uint32\"},{\"internalType\":\"bytes\",\"name\":\"message\",\"type\":\"bytes\"}],\"name\":\"deposit\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"}],\"devdoc\":{\"custom:security-contact\":\"bugs@across.to\",\"details\":\"This contract must be deployed via Create2 to the same address on all chains. That way, an errant transaction sent to the wrong chain will be blocked by this contract rather than hitting a dead address. This means that this contract will not work to protect chains, like zkSync, where Create2 address derivations don't match other chains. Source: https://era.zksync.io/docs/reference/architecture/differences-with-ethereum.html#create-create2\",\"kind\":\"dev\",\"methods\":{\"deposit(address,address,address,uint256,uint256,uint256,address,uint32,uint32,uint32,bytes)\":{\"details\":\"Protects the caller from losing their ETH (or other native token) by reverting if the SpokePool address they intended to call does not exist on this chain. Because this contract can be deployed at the same address everywhere callers should be protected even if the transaction is submitted to an unintended network. This contract should only be used for native token deposits, as this problem only exists for native tokens.\",\"params\":{\"destinationChainId\":\"Denotes network where user will receive funds from SpokePool by a relayer.\",\"exclusiveRelayer\":\"Address of the relayer who has exclusive rights to fill this deposit. Can be set to 0x0 if no exclusivity period is desired. If so, then must set exclusivityDeadline to 0.\",\"exclusivityDeadline\":\"Timestamp after which any relayer can fill this deposit. Must set to 0 if exclusiveRelayer is set to 0x0, and vice versa.\",\"fillDeadline\":\"Timestamp after which this deposit can no longer be filled.\",\"inputAmount\":\"Amount of tokens to deposit.\",\"inputToken\":\"Token to lock into this contract to initiate deposit.\",\"message\":\"Arbitrary data that can be used to pass additional information to the recipient along with the tokens. Note: this is intended to be used to pass along instructions for how a contract should use or allocate the tokens.\",\"outputAmount\":\"Amount of tokens to receive on destination chain.\",\"quoteTimestamp\":\"Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid to LP pool on HubPool.\",\"recipient\":\"Address to receive funds at on destination chain.\",\"spokePool\":\"Address of the SpokePool contract that the user is intending to call.\"}}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"deposit(address,address,address,uint256,uint256,uint256,address,uint32,uint32,uint32,bytes)\":{\"notice\":\"Passthrough function to `depositV3()` on the SpokePool contract.\"}},\"notice\":\"SpokePoolVerifier is a contract that verifies that the SpokePool exists on this chain before sending ETH to it.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/SpokePoolVerifier.sol\":\"SpokePoolVerifier\"},\"debug\":{\"revertStrings\":\"strip\"},\"evmVersion\":\"paris\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":1000000},\"remappings\":[],\"viaIR\":true},\"sources\":{\"@openzeppelin/contracts/utils/Address.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.9.0) (utils/Address.sol)\\n\\npragma solidity ^0.8.1;\\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 * Furthermore, `isContract` will also return true if the target contract within\\n * the same transaction is already scheduled for destruction by `SELFDESTRUCT`,\\n * which only has an effect at the end of a transaction.\\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 > 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://consensys.net/diligence/blog/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.8.0/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\\n */\\n function sendValue(address payable recipient, uint256 amount) internal {\\n require(address(this).balance >= amount, \\\"Address: insufficient balance\\\");\\n\\n (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 functionCallWithValue(target, data, 0, \\\"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(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, value, \\\"Address: low-level call with value failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\\n * with `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(address(this).balance >= value, \\\"Address: insufficient balance for call\\\");\\n (bool success, bytes memory returndata) = target.call{value: value}(data);\\n return verifyCallResultFromTarget(target, 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 (bool success, bytes memory returndata) = target.staticcall(data);\\n return verifyCallResultFromTarget(target, 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 (bool success, bytes memory returndata) = target.delegatecall(data);\\n return verifyCallResultFromTarget(target, success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling\\n * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.\\n *\\n * _Available since v4.8._\\n */\\n function verifyCallResultFromTarget(\\n address target,\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n if (success) {\\n if (returndata.length == 0) {\\n // only check isContract if the call was successful and the return data is empty\\n // otherwise we already know that it was a contract\\n require(isContract(target), \\\"Address: call to non-contract\\\");\\n }\\n return returndata;\\n } else {\\n _revert(returndata, errorMessage);\\n }\\n }\\n\\n /**\\n * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the\\n * revert reason or 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 _revert(returndata, errorMessage);\\n }\\n }\\n\\n function _revert(bytes memory returndata, string memory errorMessage) private pure {\\n // Look for revert reason and bubble it up if present\\n if (returndata.length > 0) {\\n // The easiest way to bubble the revert reason is using memory via assembly\\n /// @solidity memory-safe-assembly\\n assembly {\\n let returndata_size := mload(returndata)\\n revert(add(32, returndata), returndata_size)\\n }\\n } else {\\n revert(errorMessage);\\n }\\n }\\n}\\n\",\"keccak256\":\"0x006dd67219697fe68d7fbfdea512e7c4cb64a43565ed86171d67e844982da6fa\",\"license\":\"MIT\"},\"contracts/SpokePoolVerifier.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\nimport \\\"@openzeppelin/contracts/utils/Address.sol\\\";\\nimport \\\"./interfaces/V3SpokePoolInterface.sol\\\";\\n\\n/**\\n * @notice SpokePoolVerifier is a contract that verifies that the SpokePool exists on this chain before sending ETH to it.\\n * @dev This contract must be deployed via Create2 to the same address on all chains. That way, an errant transaction sent\\n * to the wrong chain will be blocked by this contract rather than hitting a dead address. This means that this contract\\n * will not work to protect chains, like zkSync, where Create2 address derivations don't match other chains.\\n * Source: https://era.zksync.io/docs/reference/architecture/differences-with-ethereum.html#create-create2\\n * @custom:security-contact bugs@across.to\\n */\\ncontract SpokePoolVerifier {\\n using Address for address;\\n\\n /**\\n * @notice Passthrough function to `depositV3()` on the SpokePool contract.\\n * @dev Protects the caller from losing their ETH (or other native token) by reverting if the SpokePool address\\n * they intended to call does not exist on this chain. Because this contract can be deployed at the same address\\n * everywhere callers should be protected even if the transaction is submitted to an unintended network.\\n * This contract should only be used for native token deposits, as this problem only exists for native tokens.\\n * @param spokePool Address of the SpokePool contract that the user is intending to call.\\n * @param recipient Address to receive funds at on destination chain.\\n * @param inputToken Token to lock into this contract to initiate deposit.\\n * @param inputAmount Amount of tokens to deposit.\\n * @param outputAmount Amount of tokens to receive on destination chain.\\n * @param destinationChainId Denotes network where user will receive funds from SpokePool by a relayer.\\n * @param quoteTimestamp Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid\\n * to LP pool on HubPool.\\n * @param message Arbitrary data that can be used to pass additional information to the recipient along with the tokens.\\n * Note: this is intended to be used to pass along instructions for how a contract should use or allocate the tokens.\\n * @param exclusiveRelayer Address of the relayer who has exclusive rights to fill this deposit. Can be set to\\n * 0x0 if no exclusivity period is desired. If so, then must set exclusivityDeadline to 0.\\n * @param exclusivityDeadline Timestamp after which any relayer can fill this deposit. Must set\\n * to 0 if exclusiveRelayer is set to 0x0, and vice versa.\\n * @param fillDeadline Timestamp after which this deposit can no longer be filled.\\n */\\n function deposit(\\n V3SpokePoolInterface spokePool,\\n address recipient,\\n address inputToken,\\n uint256 inputAmount,\\n uint256 outputAmount,\\n uint256 destinationChainId,\\n address exclusiveRelayer,\\n uint32 quoteTimestamp,\\n uint32 fillDeadline,\\n uint32 exclusivityDeadline,\\n bytes memory message\\n ) external payable {\\n require(msg.value == inputAmount, \\\"msg.value != amount\\\");\\n require(address(spokePool).isContract(), \\\"spokePool is not a contract\\\");\\n // Set msg.sender as the depositor so that msg.sender can speed up the deposit.\\n spokePool.depositV3{ value: msg.value }(\\n msg.sender,\\n recipient,\\n inputToken,\\n // @dev Setting outputToken to 0x0 to instruct fillers to use the equivalent token\\n // as the originToken on the destination chain.\\n address(0),\\n inputAmount,\\n outputAmount,\\n destinationChainId,\\n exclusiveRelayer,\\n quoteTimestamp,\\n fillDeadline,\\n exclusivityDeadline,\\n message\\n );\\n }\\n}\\n\",\"keccak256\":\"0xd5b1ec1b7048634a8b0a7e1e2c68ce51e410157b14778a207b64aff49bc5c6f0\",\"license\":\"BUSL-1.1\"},\"contracts/interfaces/V3SpokePoolInterface.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\n// Contains structs and functions used by SpokePool contracts to facilitate universal settlement.\\ninterface V3SpokePoolInterface {\\n /**************************************\\n * ENUMS *\\n **************************************/\\n\\n // Fill status tracks on-chain state of deposit, uniquely identified by relayHash.\\n enum FillStatus {\\n Unfilled,\\n RequestedSlowFill,\\n Filled\\n }\\n // Fill type is emitted in the FilledRelay event to assist Dataworker with determining which types of\\n // fills to refund (e.g. only fast fills) and whether a fast fill created a sow fill excess.\\n enum FillType {\\n FastFill,\\n // Fast fills are normal fills that do not replace a slow fill request.\\n ReplacedSlowFill,\\n // Replaced slow fills are fast fills that replace a slow fill request. This type is used by the Dataworker\\n // to know when to send excess funds from the SpokePool to the HubPool because they can no longer be used\\n // for a slow fill execution.\\n SlowFill\\n // Slow fills are requested via requestSlowFill and executed by executeSlowRelayLeaf after a bundle containing\\n // the slow fill is validated.\\n }\\n\\n /**************************************\\n * STRUCTS *\\n **************************************/\\n\\n // This struct represents the data to fully specify a **unique** relay submitted on this chain.\\n // This data is hashed with the chainId() and saved by the SpokePool to prevent collisions and protect against\\n // replay attacks on other chains. If any portion of this data differs, the relay is considered to be\\n // completely distinct.\\n struct V3RelayData {\\n // The address that made the deposit on the origin chain.\\n address depositor;\\n // The recipient address on the destination chain.\\n address recipient;\\n // This is the exclusive relayer who can fill the deposit before the exclusivity deadline.\\n address exclusiveRelayer;\\n // Token that is deposited on origin chain by depositor.\\n address inputToken;\\n // Token that is received on destination chain by recipient.\\n address outputToken;\\n // The amount of input token deposited by depositor.\\n uint256 inputAmount;\\n // The amount of output token to be received by recipient.\\n uint256 outputAmount;\\n // Origin chain id.\\n uint256 originChainId;\\n // The id uniquely identifying this deposit on the origin chain.\\n uint32 depositId;\\n // The timestamp on the destination chain after which this deposit can no longer be filled.\\n uint32 fillDeadline;\\n // The timestamp on the destination chain after which any relayer can fill the deposit.\\n uint32 exclusivityDeadline;\\n // Data that is forwarded to the recipient.\\n bytes message;\\n }\\n\\n // Contains parameters passed in by someone who wants to execute a slow relay leaf.\\n struct V3SlowFill {\\n V3RelayData relayData;\\n uint256 chainId;\\n uint256 updatedOutputAmount;\\n }\\n\\n // Contains information about a relay to be sent along with additional information that is not unique to the\\n // relay itself but is required to know how to process the relay. For example, \\\"updatedX\\\" fields can be used\\n // by the relayer to modify fields of the relay with the depositor's permission, and \\\"repaymentChainId\\\" is specified\\n // by the relayer to determine where to take a relayer refund, but doesn't affect the uniqueness of the relay.\\n struct V3RelayExecutionParams {\\n V3RelayData relay;\\n bytes32 relayHash;\\n uint256 updatedOutputAmount;\\n address updatedRecipient;\\n bytes updatedMessage;\\n uint256 repaymentChainId;\\n }\\n\\n // Packs together parameters emitted in FilledV3Relay because there are too many emitted otherwise.\\n // Similar to V3RelayExecutionParams, these parameters are not used to uniquely identify the deposit being\\n // filled so they don't have to be unpacked by all clients.\\n struct V3RelayExecutionEventInfo {\\n address updatedRecipient;\\n bytes updatedMessage;\\n uint256 updatedOutputAmount;\\n FillType fillType;\\n }\\n\\n /**************************************\\n * EVENTS *\\n **************************************/\\n\\n event V3FundsDeposited(\\n address inputToken,\\n address outputToken,\\n uint256 inputAmount,\\n uint256 outputAmount,\\n uint256 indexed destinationChainId,\\n uint32 indexed depositId,\\n uint32 quoteTimestamp,\\n uint32 fillDeadline,\\n uint32 exclusivityDeadline,\\n address indexed depositor,\\n address recipient,\\n address exclusiveRelayer,\\n bytes message\\n );\\n\\n event RequestedSpeedUpV3Deposit(\\n uint256 updatedOutputAmount,\\n uint32 indexed depositId,\\n address indexed depositor,\\n address updatedRecipient,\\n bytes updatedMessage,\\n bytes depositorSignature\\n );\\n\\n event FilledV3Relay(\\n address inputToken,\\n address outputToken,\\n uint256 inputAmount,\\n uint256 outputAmount,\\n uint256 repaymentChainId,\\n uint256 indexed originChainId,\\n uint32 indexed depositId,\\n uint32 fillDeadline,\\n uint32 exclusivityDeadline,\\n address exclusiveRelayer,\\n address indexed relayer,\\n address depositor,\\n address recipient,\\n bytes message,\\n V3RelayExecutionEventInfo relayExecutionInfo\\n );\\n\\n event RequestedV3SlowFill(\\n address inputToken,\\n address outputToken,\\n uint256 inputAmount,\\n uint256 outputAmount,\\n uint256 indexed originChainId,\\n uint32 indexed depositId,\\n uint32 fillDeadline,\\n uint32 exclusivityDeadline,\\n address exclusiveRelayer,\\n address depositor,\\n address recipient,\\n bytes message\\n );\\n\\n /**************************************\\n * FUNCTIONS *\\n **************************************/\\n\\n function depositV3(\\n address depositor,\\n address recipient,\\n address inputToken,\\n address outputToken,\\n uint256 inputAmount,\\n uint256 outputAmount,\\n uint256 destinationChainId,\\n address exclusiveRelayer,\\n uint32 quoteTimestamp,\\n uint32 fillDeadline,\\n uint32 exclusivityDeadline,\\n bytes calldata message\\n ) external payable;\\n\\n function depositV3Now(\\n address depositor,\\n address recipient,\\n address inputToken,\\n address outputToken,\\n uint256 inputAmount,\\n uint256 outputAmount,\\n uint256 destinationChainId,\\n address exclusiveRelayer,\\n uint32 fillDeadlineOffset,\\n uint32 exclusivityDeadline,\\n bytes calldata message\\n ) external payable;\\n\\n function speedUpV3Deposit(\\n address depositor,\\n uint32 depositId,\\n uint256 updatedOutputAmount,\\n address updatedRecipient,\\n bytes calldata updatedMessage,\\n bytes calldata depositorSignature\\n ) external;\\n\\n function fillV3Relay(V3RelayData calldata relayData, uint256 repaymentChainId) external;\\n\\n function fillV3RelayWithUpdatedDeposit(\\n V3RelayData calldata relayData,\\n uint256 repaymentChainId,\\n uint256 updatedOutputAmount,\\n address updatedRecipient,\\n bytes calldata updatedMessage,\\n bytes calldata depositorSignature\\n ) external;\\n\\n function requestV3SlowFill(V3RelayData calldata relayData) external;\\n\\n function executeV3SlowRelayLeaf(\\n V3SlowFill calldata slowFillLeaf,\\n uint32 rootBundleId,\\n bytes32[] calldata proof\\n ) external;\\n\\n /**************************************\\n * ERRORS *\\n **************************************/\\n\\n error DisabledRoute();\\n error InvalidQuoteTimestamp();\\n error InvalidFillDeadline();\\n error InvalidExclusiveRelayer();\\n error InvalidExclusivityDeadline();\\n error MsgValueDoesNotMatchInputAmount();\\n error NotExclusiveRelayer();\\n error NoSlowFillsInExclusivityWindow();\\n error RelayFilled();\\n error InvalidSlowFillRequest();\\n error ExpiredFillDeadline();\\n error InvalidMerkleProof();\\n error InvalidChainId();\\n error InvalidMerkleLeaf();\\n error ClaimedMerkleLeaf();\\n error InvalidPayoutAdjustmentPct();\\n}\\n\",\"keccak256\":\"0x374b7e9cb8afbcaec69cdbcde480676b5d927db84c7f38221331d1226af68d9d\",\"license\":\"BUSL-1.1\"}},\"version\":1}", + "bytecode": "0x60808060405234610016576103a4908161001c8239f35b600080fdfe600436101561000d57600080fd5b6000803560e01c63902e949c1461002357600080fd5b6101607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261036b5773ffffffffffffffffffffffffffffffffffffffff6004358181168103610367576024359082821682036103635760443591838316830361035f5760c435848116810361035b5760e4359063ffffffff928383168303610357576101043590848216820361035357610124359385851685036103225767ffffffffffffffff610144351161032257366023610144350112156103225767ffffffffffffffff6101443560040135116103265767ffffffffffffffff6004610144350135601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f0116608090810191821191101761032657608060046101443590810135601f81017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f011683016040529182905236910160240111610322576101443560048101359060240160a03760a06004610144350135018a90526064353403610322578887163b15610322578887163b1561032257918589979593888296818e9c60409e9b979e519e8f9d8e917f7b9392320000000000000000000000000000000000000000000000000000000083523360048401521690602401521660448c01528b60648c015260643560848c015260843560a48c015260a43560c48c01521660e48a01521661010488015216610124860152166101448401526101648301610180905260805180610184850152845b8181106103075750908391827fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f6101a49389858286010152011681010301923491165af180156102fc576102ba575080f35b67ffffffffffffffff81116102cf5760405280f35b6024827f4e487b710000000000000000000000000000000000000000000000000000000081526041600452fd5b6040513d84823e3d90fd5b60a08101518782016101a40152879550869450602001610266565b8980fd5b60248a7f4e487b710000000000000000000000000000000000000000000000000000000081526041600452fd5b8880fd5b8780fd5b8580fd5b8480fd5b8380fd5b8280fd5b80fdfea26469706673582212201ceff237e6adbd0d3f92e892f7f3f51306c23eac5f7e3f896c2c723d9e5be3a664736f6c63430008130033", + "deployedBytecode": "0x600436101561000d57600080fd5b6000803560e01c63902e949c1461002357600080fd5b6101607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261036b5773ffffffffffffffffffffffffffffffffffffffff6004358181168103610367576024359082821682036103635760443591838316830361035f5760c435848116810361035b5760e4359063ffffffff928383168303610357576101043590848216820361035357610124359385851685036103225767ffffffffffffffff610144351161032257366023610144350112156103225767ffffffffffffffff6101443560040135116103265767ffffffffffffffff6004610144350135601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f0116608090810191821191101761032657608060046101443590810135601f81017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f011683016040529182905236910160240111610322576101443560048101359060240160a03760a06004610144350135018a90526064353403610322578887163b15610322578887163b1561032257918589979593888296818e9c60409e9b979e519e8f9d8e917f7b9392320000000000000000000000000000000000000000000000000000000083523360048401521690602401521660448c01528b60648c015260643560848c015260843560a48c015260a43560c48c01521660e48a01521661010488015216610124860152166101448401526101648301610180905260805180610184850152845b8181106103075750908391827fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f6101a49389858286010152011681010301923491165af180156102fc576102ba575080f35b67ffffffffffffffff81116102cf5760405280f35b6024827f4e487b710000000000000000000000000000000000000000000000000000000081526041600452fd5b6040513d84823e3d90fd5b60a08101518782016101a40152879550869450602001610266565b8980fd5b60248a7f4e487b710000000000000000000000000000000000000000000000000000000081526041600452fd5b8880fd5b8780fd5b8580fd5b8480fd5b8380fd5b8280fd5b80fdfea26469706673582212201ceff237e6adbd0d3f92e892f7f3f51306c23eac5f7e3f896c2c723d9e5be3a664736f6c63430008130033", "devdoc": { + "custom:security-contact": "bugs@across.to", "details": "This contract must be deployed via Create2 to the same address on all chains. That way, an errant transaction sent to the wrong chain will be blocked by this contract rather than hitting a dead address. This means that this contract will not work to protect chains, like zkSync, where Create2 address derivations don't match other chains. Source: https://era.zksync.io/docs/reference/architecture/differences-with-ethereum.html#create-create2", "kind": "dev", "methods": { - "deposit(address,address,address,uint256,uint256,int64,uint32,bytes,uint256)": { + "deposit(address,address,address,uint256,uint256,uint256,address,uint32,uint32,uint32,bytes)": { "details": "Protects the caller from losing their ETH (or other native token) by reverting if the SpokePool address they intended to call does not exist on this chain. Because this contract can be deployed at the same address everywhere callers should be protected even if the transaction is submitted to an unintended network. This contract should only be used for native token deposits, as this problem only exists for native tokens.", "params": { - "amount": "Amount of tokens to deposit. Will be amount of tokens to receive less fees.", "destinationChainId": "Denotes network where user will receive funds from SpokePool by a relayer.", - "maxCount": "used to protect the depositor from frontrunning to guarantee their quote remains valid. Note: this is intended to be used to pass along instructions for how a contract should use or allocate the tokens.", + "exclusiveRelayer": "Address of the relayer who has exclusive rights to fill this deposit. Can be set to 0x0 if no exclusivity period is desired. If so, then must set exclusivityDeadline to 0.", + "exclusivityDeadline": "Timestamp after which any relayer can fill this deposit. Must set to 0 if exclusiveRelayer is set to 0x0, and vice versa.", + "fillDeadline": "Timestamp after which this deposit can no longer be filled.", + "inputAmount": "Amount of tokens to deposit.", + "inputToken": "Token to lock into this contract to initiate deposit.", "message": "Arbitrary data that can be used to pass additional information to the recipient along with the tokens. Note: this is intended to be used to pass along instructions for how a contract should use or allocate the tokens.", - "originToken": "Token to lock into this contract to initiate deposit.", + "outputAmount": "Amount of tokens to receive on destination chain.", "quoteTimestamp": "Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid to LP pool on HubPool.", "recipient": "Address to receive funds at on destination chain.", - "relayerFeePct": "% of deposit amount taken out to incentivize a fast relayer.", "spokePool": "Address of the SpokePool contract that the user is intending to call." } } @@ -101,7 +114,7 @@ "userdoc": { "kind": "user", "methods": { - "deposit(address,address,address,uint256,uint256,int64,uint32,bytes,uint256)": { + "deposit(address,address,address,uint256,uint256,uint256,address,uint32,uint32,uint32,bytes)": { "notice": "Passthrough function to `depositV3()` on the SpokePool contract." } }, diff --git a/deployments/optimism/solcInputs/1a67233dfe969c05446730f26ab1d2c8.json b/deployments/optimism/solcInputs/1a67233dfe969c05446730f26ab1d2c8.json new file mode 100644 index 000000000..96daeb1aa --- /dev/null +++ b/deployments/optimism/solcInputs/1a67233dfe969c05446730f26ab1d2c8.json @@ -0,0 +1,43 @@ +{ + "language": "Solidity", + "sources": { + "@openzeppelin/contracts/utils/Address.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (utils/Address.sol)\n\npragma solidity ^0.8.1;\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 * Furthermore, `isContract` will also return true if the target contract within\n * the same transaction is already scheduled for destruction by `SELFDESTRUCT`,\n * which only has an effect at the end of a transaction.\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 > 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://consensys.net/diligence/blog/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.8.0/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n require(address(this).balance >= amount, \"Address: insufficient balance\");\n\n (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 functionCallWithValue(target, data, 0, \"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(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n return functionCallWithValue(target, data, value, \"Address: low-level call with value failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\n * with `errorMessage` as a fallback revert reason when `target` reverts.\n *\n * _Available since v3.1._\n */\n function functionCallWithValue(\n address target,\n bytes memory data,\n uint256 value,\n string memory errorMessage\n ) internal returns (bytes memory) {\n require(address(this).balance >= value, \"Address: insufficient balance for call\");\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, 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 (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, 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 (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata, errorMessage);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling\n * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.\n *\n * _Available since v4.8._\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata,\n string memory errorMessage\n ) internal view returns (bytes memory) {\n if (success) {\n if (returndata.length == 0) {\n // only check isContract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n require(isContract(target), \"Address: call to non-contract\");\n }\n return returndata;\n } else {\n _revert(returndata, errorMessage);\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the\n * revert reason or 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 _revert(returndata, errorMessage);\n }\n }\n\n function _revert(bytes memory returndata, string memory errorMessage) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length > 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert(errorMessage);\n }\n }\n}\n" + }, + "contracts/interfaces/V3SpokePoolInterface.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n// Contains structs and functions used by SpokePool contracts to facilitate universal settlement.\ninterface V3SpokePoolInterface {\n /**************************************\n * ENUMS *\n **************************************/\n\n // Fill status tracks on-chain state of deposit, uniquely identified by relayHash.\n enum FillStatus {\n Unfilled,\n RequestedSlowFill,\n Filled\n }\n // Fill type is emitted in the FilledRelay event to assist Dataworker with determining which types of\n // fills to refund (e.g. only fast fills) and whether a fast fill created a sow fill excess.\n enum FillType {\n FastFill,\n // Fast fills are normal fills that do not replace a slow fill request.\n ReplacedSlowFill,\n // Replaced slow fills are fast fills that replace a slow fill request. This type is used by the Dataworker\n // to know when to send excess funds from the SpokePool to the HubPool because they can no longer be used\n // for a slow fill execution.\n SlowFill\n // Slow fills are requested via requestSlowFill and executed by executeSlowRelayLeaf after a bundle containing\n // the slow fill is validated.\n }\n\n /**************************************\n * STRUCTS *\n **************************************/\n\n // This struct represents the data to fully specify a **unique** relay submitted on this chain.\n // This data is hashed with the chainId() and saved by the SpokePool to prevent collisions and protect against\n // replay attacks on other chains. If any portion of this data differs, the relay is considered to be\n // completely distinct.\n struct V3RelayData {\n // The address that made the deposit on the origin chain.\n address depositor;\n // The recipient address on the destination chain.\n address recipient;\n // This is the exclusive relayer who can fill the deposit before the exclusivity deadline.\n address exclusiveRelayer;\n // Token that is deposited on origin chain by depositor.\n address inputToken;\n // Token that is received on destination chain by recipient.\n address outputToken;\n // The amount of input token deposited by depositor.\n uint256 inputAmount;\n // The amount of output token to be received by recipient.\n uint256 outputAmount;\n // Origin chain id.\n uint256 originChainId;\n // The id uniquely identifying this deposit on the origin chain.\n uint32 depositId;\n // The timestamp on the destination chain after which this deposit can no longer be filled.\n uint32 fillDeadline;\n // The timestamp on the destination chain after which any relayer can fill the deposit.\n uint32 exclusivityDeadline;\n // Data that is forwarded to the recipient.\n bytes message;\n }\n\n // Contains parameters passed in by someone who wants to execute a slow relay leaf.\n struct V3SlowFill {\n V3RelayData relayData;\n uint256 chainId;\n uint256 updatedOutputAmount;\n }\n\n // Contains information about a relay to be sent along with additional information that is not unique to the\n // relay itself but is required to know how to process the relay. For example, \"updatedX\" fields can be used\n // by the relayer to modify fields of the relay with the depositor's permission, and \"repaymentChainId\" is specified\n // by the relayer to determine where to take a relayer refund, but doesn't affect the uniqueness of the relay.\n struct V3RelayExecutionParams {\n V3RelayData relay;\n bytes32 relayHash;\n uint256 updatedOutputAmount;\n address updatedRecipient;\n bytes updatedMessage;\n uint256 repaymentChainId;\n }\n\n // Packs together parameters emitted in FilledV3Relay because there are too many emitted otherwise.\n // Similar to V3RelayExecutionParams, these parameters are not used to uniquely identify the deposit being\n // filled so they don't have to be unpacked by all clients.\n struct V3RelayExecutionEventInfo {\n address updatedRecipient;\n bytes updatedMessage;\n uint256 updatedOutputAmount;\n FillType fillType;\n }\n\n /**************************************\n * EVENTS *\n **************************************/\n\n event V3FundsDeposited(\n address inputToken,\n address outputToken,\n uint256 inputAmount,\n uint256 outputAmount,\n uint256 indexed destinationChainId,\n uint32 indexed depositId,\n uint32 quoteTimestamp,\n uint32 fillDeadline,\n uint32 exclusivityDeadline,\n address indexed depositor,\n address recipient,\n address exclusiveRelayer,\n bytes message\n );\n\n event RequestedSpeedUpV3Deposit(\n uint256 updatedOutputAmount,\n uint32 indexed depositId,\n address indexed depositor,\n address updatedRecipient,\n bytes updatedMessage,\n bytes depositorSignature\n );\n\n event FilledV3Relay(\n address inputToken,\n address outputToken,\n uint256 inputAmount,\n uint256 outputAmount,\n uint256 repaymentChainId,\n uint256 indexed originChainId,\n uint32 indexed depositId,\n uint32 fillDeadline,\n uint32 exclusivityDeadline,\n address exclusiveRelayer,\n address indexed relayer,\n address depositor,\n address recipient,\n bytes message,\n V3RelayExecutionEventInfo relayExecutionInfo\n );\n\n event RequestedV3SlowFill(\n address inputToken,\n address outputToken,\n uint256 inputAmount,\n uint256 outputAmount,\n uint256 indexed originChainId,\n uint32 indexed depositId,\n uint32 fillDeadline,\n uint32 exclusivityDeadline,\n address exclusiveRelayer,\n address depositor,\n address recipient,\n bytes message\n );\n\n /**************************************\n * FUNCTIONS *\n **************************************/\n\n function depositV3(\n address depositor,\n address recipient,\n address inputToken,\n address outputToken,\n uint256 inputAmount,\n uint256 outputAmount,\n uint256 destinationChainId,\n address exclusiveRelayer,\n uint32 quoteTimestamp,\n uint32 fillDeadline,\n uint32 exclusivityDeadline,\n bytes calldata message\n ) external payable;\n\n function depositV3Now(\n address depositor,\n address recipient,\n address inputToken,\n address outputToken,\n uint256 inputAmount,\n uint256 outputAmount,\n uint256 destinationChainId,\n address exclusiveRelayer,\n uint32 fillDeadlineOffset,\n uint32 exclusivityDeadline,\n bytes calldata message\n ) external payable;\n\n function speedUpV3Deposit(\n address depositor,\n uint32 depositId,\n uint256 updatedOutputAmount,\n address updatedRecipient,\n bytes calldata updatedMessage,\n bytes calldata depositorSignature\n ) external;\n\n function fillV3Relay(V3RelayData calldata relayData, uint256 repaymentChainId) external;\n\n function fillV3RelayWithUpdatedDeposit(\n V3RelayData calldata relayData,\n uint256 repaymentChainId,\n uint256 updatedOutputAmount,\n address updatedRecipient,\n bytes calldata updatedMessage,\n bytes calldata depositorSignature\n ) external;\n\n function requestV3SlowFill(V3RelayData calldata relayData) external;\n\n function executeV3SlowRelayLeaf(\n V3SlowFill calldata slowFillLeaf,\n uint32 rootBundleId,\n bytes32[] calldata proof\n ) external;\n\n /**************************************\n * ERRORS *\n **************************************/\n\n error DisabledRoute();\n error InvalidQuoteTimestamp();\n error InvalidFillDeadline();\n error InvalidExclusiveRelayer();\n error InvalidExclusivityDeadline();\n error MsgValueDoesNotMatchInputAmount();\n error NotExclusiveRelayer();\n error NoSlowFillsInExclusivityWindow();\n error RelayFilled();\n error InvalidSlowFillRequest();\n error ExpiredFillDeadline();\n error InvalidMerkleProof();\n error InvalidChainId();\n error InvalidMerkleLeaf();\n error ClaimedMerkleLeaf();\n error InvalidPayoutAdjustmentPct();\n}\n" + }, + "contracts/SpokePoolVerifier.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/utils/Address.sol\";\nimport \"./interfaces/V3SpokePoolInterface.sol\";\n\n/**\n * @notice SpokePoolVerifier is a contract that verifies that the SpokePool exists on this chain before sending ETH to it.\n * @dev This contract must be deployed via Create2 to the same address on all chains. That way, an errant transaction sent\n * to the wrong chain will be blocked by this contract rather than hitting a dead address. This means that this contract\n * will not work to protect chains, like zkSync, where Create2 address derivations don't match other chains.\n * Source: https://era.zksync.io/docs/reference/architecture/differences-with-ethereum.html#create-create2\n * @custom:security-contact bugs@across.to\n */\ncontract SpokePoolVerifier {\n using Address for address;\n\n /**\n * @notice Passthrough function to `depositV3()` on the SpokePool contract.\n * @dev Protects the caller from losing their ETH (or other native token) by reverting if the SpokePool address\n * they intended to call does not exist on this chain. Because this contract can be deployed at the same address\n * everywhere callers should be protected even if the transaction is submitted to an unintended network.\n * This contract should only be used for native token deposits, as this problem only exists for native tokens.\n * @param spokePool Address of the SpokePool contract that the user is intending to call.\n * @param recipient Address to receive funds at on destination chain.\n * @param inputToken Token to lock into this contract to initiate deposit.\n * @param inputAmount Amount of tokens to deposit.\n * @param outputAmount Amount of tokens to receive on destination chain.\n * @param destinationChainId Denotes network where user will receive funds from SpokePool by a relayer.\n * @param quoteTimestamp Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid\n * to LP pool on HubPool.\n * @param message Arbitrary data that can be used to pass additional information to the recipient along with the tokens.\n * Note: this is intended to be used to pass along instructions for how a contract should use or allocate the tokens.\n * @param exclusiveRelayer Address of the relayer who has exclusive rights to fill this deposit. Can be set to\n * 0x0 if no exclusivity period is desired. If so, then must set exclusivityDeadline to 0.\n * @param exclusivityDeadline Timestamp after which any relayer can fill this deposit. Must set\n * to 0 if exclusiveRelayer is set to 0x0, and vice versa.\n * @param fillDeadline Timestamp after which this deposit can no longer be filled.\n */\n function deposit(\n V3SpokePoolInterface spokePool,\n address recipient,\n address inputToken,\n uint256 inputAmount,\n uint256 outputAmount,\n uint256 destinationChainId,\n uint32 quoteTimestamp,\n bytes memory message,\n address exclusiveRelayer,\n uint32 exclusivityDeadline,\n uint32 fillDeadline\n ) external payable {\n require(msg.value == inputAmount, \"msg.value != amount\");\n require(address(spokePool).isContract(), \"spokePool is not a contract\");\n // Set msg.sender as the depositor so that msg.sender can speed up the deposit.\n spokePool.depositV3{ value: msg.value }(\n msg.sender,\n recipient,\n inputToken,\n // @dev Setting outputToken to 0x0 to instruct fillers to use the equivalent token\n // as the originToken on the destination chain.\n address(0),\n inputAmount,\n outputAmount,\n destinationChainId,\n exclusiveRelayer,\n quoteTimestamp,\n fillDeadline,\n exclusivityDeadline,\n message\n );\n }\n}\n" + } + }, + "settings": { + "optimizer": { + "enabled": true, + "runs": 1000000 + }, + "viaIR": true, + "debug": { + "revertStrings": "strip" + }, + "outputSelection": { + "*": { + "*": [ + "abi", + "evm.bytecode", + "evm.deployedBytecode", + "evm.methodIdentifiers", + "metadata", + "devdoc", + "userdoc", + "storageLayout", + "evm.gasEstimates" + ], + "": ["ast"] + } + }, + "metadata": { + "useLiteralContent": true + } + } +} diff --git a/deployments/optimism/solcInputs/783274f805324492b21545b62eb0dbfe.json b/deployments/optimism/solcInputs/783274f805324492b21545b62eb0dbfe.json new file mode 100644 index 000000000..4bcffc07b --- /dev/null +++ b/deployments/optimism/solcInputs/783274f805324492b21545b62eb0dbfe.json @@ -0,0 +1,43 @@ +{ + "language": "Solidity", + "sources": { + "@openzeppelin/contracts/utils/Address.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (utils/Address.sol)\n\npragma solidity ^0.8.1;\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 * Furthermore, `isContract` will also return true if the target contract within\n * the same transaction is already scheduled for destruction by `SELFDESTRUCT`,\n * which only has an effect at the end of a transaction.\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 > 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://consensys.net/diligence/blog/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.8.0/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n require(address(this).balance >= amount, \"Address: insufficient balance\");\n\n (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 functionCallWithValue(target, data, 0, \"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(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n return functionCallWithValue(target, data, value, \"Address: low-level call with value failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\n * with `errorMessage` as a fallback revert reason when `target` reverts.\n *\n * _Available since v3.1._\n */\n function functionCallWithValue(\n address target,\n bytes memory data,\n uint256 value,\n string memory errorMessage\n ) internal returns (bytes memory) {\n require(address(this).balance >= value, \"Address: insufficient balance for call\");\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, 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 (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, 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 (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata, errorMessage);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling\n * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.\n *\n * _Available since v4.8._\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata,\n string memory errorMessage\n ) internal view returns (bytes memory) {\n if (success) {\n if (returndata.length == 0) {\n // only check isContract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n require(isContract(target), \"Address: call to non-contract\");\n }\n return returndata;\n } else {\n _revert(returndata, errorMessage);\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the\n * revert reason or 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 _revert(returndata, errorMessage);\n }\n }\n\n function _revert(bytes memory returndata, string memory errorMessage) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length > 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert(errorMessage);\n }\n }\n}\n" + }, + "contracts/interfaces/V3SpokePoolInterface.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n// Contains structs and functions used by SpokePool contracts to facilitate universal settlement.\ninterface V3SpokePoolInterface {\n /**************************************\n * ENUMS *\n **************************************/\n\n // Fill status tracks on-chain state of deposit, uniquely identified by relayHash.\n enum FillStatus {\n Unfilled,\n RequestedSlowFill,\n Filled\n }\n // Fill type is emitted in the FilledRelay event to assist Dataworker with determining which types of\n // fills to refund (e.g. only fast fills) and whether a fast fill created a sow fill excess.\n enum FillType {\n FastFill,\n // Fast fills are normal fills that do not replace a slow fill request.\n ReplacedSlowFill,\n // Replaced slow fills are fast fills that replace a slow fill request. This type is used by the Dataworker\n // to know when to send excess funds from the SpokePool to the HubPool because they can no longer be used\n // for a slow fill execution.\n SlowFill\n // Slow fills are requested via requestSlowFill and executed by executeSlowRelayLeaf after a bundle containing\n // the slow fill is validated.\n }\n\n /**************************************\n * STRUCTS *\n **************************************/\n\n // This struct represents the data to fully specify a **unique** relay submitted on this chain.\n // This data is hashed with the chainId() and saved by the SpokePool to prevent collisions and protect against\n // replay attacks on other chains. If any portion of this data differs, the relay is considered to be\n // completely distinct.\n struct V3RelayData {\n // The address that made the deposit on the origin chain.\n address depositor;\n // The recipient address on the destination chain.\n address recipient;\n // This is the exclusive relayer who can fill the deposit before the exclusivity deadline.\n address exclusiveRelayer;\n // Token that is deposited on origin chain by depositor.\n address inputToken;\n // Token that is received on destination chain by recipient.\n address outputToken;\n // The amount of input token deposited by depositor.\n uint256 inputAmount;\n // The amount of output token to be received by recipient.\n uint256 outputAmount;\n // Origin chain id.\n uint256 originChainId;\n // The id uniquely identifying this deposit on the origin chain.\n uint32 depositId;\n // The timestamp on the destination chain after which this deposit can no longer be filled.\n uint32 fillDeadline;\n // The timestamp on the destination chain after which any relayer can fill the deposit.\n uint32 exclusivityDeadline;\n // Data that is forwarded to the recipient.\n bytes message;\n }\n\n // Contains parameters passed in by someone who wants to execute a slow relay leaf.\n struct V3SlowFill {\n V3RelayData relayData;\n uint256 chainId;\n uint256 updatedOutputAmount;\n }\n\n // Contains information about a relay to be sent along with additional information that is not unique to the\n // relay itself but is required to know how to process the relay. For example, \"updatedX\" fields can be used\n // by the relayer to modify fields of the relay with the depositor's permission, and \"repaymentChainId\" is specified\n // by the relayer to determine where to take a relayer refund, but doesn't affect the uniqueness of the relay.\n struct V3RelayExecutionParams {\n V3RelayData relay;\n bytes32 relayHash;\n uint256 updatedOutputAmount;\n address updatedRecipient;\n bytes updatedMessage;\n uint256 repaymentChainId;\n }\n\n // Packs together parameters emitted in FilledV3Relay because there are too many emitted otherwise.\n // Similar to V3RelayExecutionParams, these parameters are not used to uniquely identify the deposit being\n // filled so they don't have to be unpacked by all clients.\n struct V3RelayExecutionEventInfo {\n address updatedRecipient;\n bytes updatedMessage;\n uint256 updatedOutputAmount;\n FillType fillType;\n }\n\n /**************************************\n * EVENTS *\n **************************************/\n\n event V3FundsDeposited(\n address inputToken,\n address outputToken,\n uint256 inputAmount,\n uint256 outputAmount,\n uint256 indexed destinationChainId,\n uint32 indexed depositId,\n uint32 quoteTimestamp,\n uint32 fillDeadline,\n uint32 exclusivityDeadline,\n address indexed depositor,\n address recipient,\n address exclusiveRelayer,\n bytes message\n );\n\n event RequestedSpeedUpV3Deposit(\n uint256 updatedOutputAmount,\n uint32 indexed depositId,\n address indexed depositor,\n address updatedRecipient,\n bytes updatedMessage,\n bytes depositorSignature\n );\n\n event FilledV3Relay(\n address inputToken,\n address outputToken,\n uint256 inputAmount,\n uint256 outputAmount,\n uint256 repaymentChainId,\n uint256 indexed originChainId,\n uint32 indexed depositId,\n uint32 fillDeadline,\n uint32 exclusivityDeadline,\n address exclusiveRelayer,\n address indexed relayer,\n address depositor,\n address recipient,\n bytes message,\n V3RelayExecutionEventInfo relayExecutionInfo\n );\n\n event RequestedV3SlowFill(\n address inputToken,\n address outputToken,\n uint256 inputAmount,\n uint256 outputAmount,\n uint256 indexed originChainId,\n uint32 indexed depositId,\n uint32 fillDeadline,\n uint32 exclusivityDeadline,\n address exclusiveRelayer,\n address depositor,\n address recipient,\n bytes message\n );\n\n /**************************************\n * FUNCTIONS *\n **************************************/\n\n function depositV3(\n address depositor,\n address recipient,\n address inputToken,\n address outputToken,\n uint256 inputAmount,\n uint256 outputAmount,\n uint256 destinationChainId,\n address exclusiveRelayer,\n uint32 quoteTimestamp,\n uint32 fillDeadline,\n uint32 exclusivityDeadline,\n bytes calldata message\n ) external payable;\n\n function depositV3Now(\n address depositor,\n address recipient,\n address inputToken,\n address outputToken,\n uint256 inputAmount,\n uint256 outputAmount,\n uint256 destinationChainId,\n address exclusiveRelayer,\n uint32 fillDeadlineOffset,\n uint32 exclusivityDeadline,\n bytes calldata message\n ) external payable;\n\n function speedUpV3Deposit(\n address depositor,\n uint32 depositId,\n uint256 updatedOutputAmount,\n address updatedRecipient,\n bytes calldata updatedMessage,\n bytes calldata depositorSignature\n ) external;\n\n function fillV3Relay(V3RelayData calldata relayData, uint256 repaymentChainId) external;\n\n function fillV3RelayWithUpdatedDeposit(\n V3RelayData calldata relayData,\n uint256 repaymentChainId,\n uint256 updatedOutputAmount,\n address updatedRecipient,\n bytes calldata updatedMessage,\n bytes calldata depositorSignature\n ) external;\n\n function requestV3SlowFill(V3RelayData calldata relayData) external;\n\n function executeV3SlowRelayLeaf(\n V3SlowFill calldata slowFillLeaf,\n uint32 rootBundleId,\n bytes32[] calldata proof\n ) external;\n\n /**************************************\n * ERRORS *\n **************************************/\n\n error DisabledRoute();\n error InvalidQuoteTimestamp();\n error InvalidFillDeadline();\n error InvalidExclusiveRelayer();\n error InvalidExclusivityDeadline();\n error MsgValueDoesNotMatchInputAmount();\n error NotExclusiveRelayer();\n error NoSlowFillsInExclusivityWindow();\n error RelayFilled();\n error InvalidSlowFillRequest();\n error ExpiredFillDeadline();\n error InvalidMerkleProof();\n error InvalidChainId();\n error InvalidMerkleLeaf();\n error ClaimedMerkleLeaf();\n error InvalidPayoutAdjustmentPct();\n}\n" + }, + "contracts/SpokePoolVerifier.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/utils/Address.sol\";\nimport \"./interfaces/V3SpokePoolInterface.sol\";\n\n/**\n * @notice SpokePoolVerifier is a contract that verifies that the SpokePool exists on this chain before sending ETH to it.\n * @dev This contract must be deployed via Create2 to the same address on all chains. That way, an errant transaction sent\n * to the wrong chain will be blocked by this contract rather than hitting a dead address. This means that this contract\n * will not work to protect chains, like zkSync, where Create2 address derivations don't match other chains.\n * Source: https://era.zksync.io/docs/reference/architecture/differences-with-ethereum.html#create-create2\n * @custom:security-contact bugs@across.to\n */\ncontract SpokePoolVerifier {\n using Address for address;\n\n /**\n * @notice Passthrough function to `depositV3()` on the SpokePool contract.\n * @dev Protects the caller from losing their ETH (or other native token) by reverting if the SpokePool address\n * they intended to call does not exist on this chain. Because this contract can be deployed at the same address\n * everywhere callers should be protected even if the transaction is submitted to an unintended network.\n * This contract should only be used for native token deposits, as this problem only exists for native tokens.\n * @param spokePool Address of the SpokePool contract that the user is intending to call.\n * @param recipient Address to receive funds at on destination chain.\n * @param inputToken Token to lock into this contract to initiate deposit.\n * @param inputAmount Amount of tokens to deposit.\n * @param outputAmount Amount of tokens to receive on destination chain.\n * @param destinationChainId Denotes network where user will receive funds from SpokePool by a relayer.\n * @param quoteTimestamp Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid\n * to LP pool on HubPool.\n * @param message Arbitrary data that can be used to pass additional information to the recipient along with the tokens.\n * Note: this is intended to be used to pass along instructions for how a contract should use or allocate the tokens.\n * @param exclusiveRelayer Address of the relayer who has exclusive rights to fill this deposit. Can be set to\n * 0x0 if no exclusivity period is desired. If so, then must set exclusivityDeadline to 0.\n * @param exclusivityDeadline Timestamp after which any relayer can fill this deposit. Must set\n * to 0 if exclusiveRelayer is set to 0x0, and vice versa.\n * @param fillDeadline Timestamp after which this deposit can no longer be filled.\n */\n function deposit(\n V3SpokePoolInterface spokePool,\n address recipient,\n address inputToken,\n uint256 inputAmount,\n uint256 outputAmount,\n uint256 destinationChainId,\n address exclusiveRelayer,\n uint32 quoteTimestamp,\n uint32 fillDeadline,\n uint32 exclusivityDeadline,\n bytes memory message\n ) external payable {\n require(msg.value == inputAmount, \"msg.value != amount\");\n require(address(spokePool).isContract(), \"spokePool is not a contract\");\n // Set msg.sender as the depositor so that msg.sender can speed up the deposit.\n spokePool.depositV3{ value: msg.value }(\n msg.sender,\n recipient,\n inputToken,\n // @dev Setting outputToken to 0x0 to instruct fillers to use the equivalent token\n // as the originToken on the destination chain.\n address(0),\n inputAmount,\n outputAmount,\n destinationChainId,\n exclusiveRelayer,\n quoteTimestamp,\n fillDeadline,\n exclusivityDeadline,\n message\n );\n }\n}\n" + } + }, + "settings": { + "optimizer": { + "enabled": true, + "runs": 1000000 + }, + "viaIR": true, + "debug": { + "revertStrings": "strip" + }, + "outputSelection": { + "*": { + "*": [ + "abi", + "evm.bytecode", + "evm.deployedBytecode", + "evm.methodIdentifiers", + "metadata", + "devdoc", + "userdoc", + "storageLayout", + "evm.gasEstimates" + ], + "": ["ast"] + } + }, + "metadata": { + "useLiteralContent": true + } + } +} diff --git a/deployments/polygon/SpokePoolVerifier.json b/deployments/polygon/SpokePoolVerifier.json index c61928a6f..c5133f255 100644 --- a/deployments/polygon/SpokePoolVerifier.json +++ b/deployments/polygon/SpokePoolVerifier.json @@ -1,10 +1,10 @@ { - "address": "0xB4A8d45647445EA9FC3E1058096142390683dBC2", + "address": "0x4437A1Ee2dFb72954F21A44C3F0F0E2CBA5A5C27", "abi": [ { "inputs": [ { - "internalType": "contract SpokePoolInterface", + "internalType": "contract V3SpokePoolInterface", "name": "spokePool", "type": "address" }, @@ -15,12 +15,17 @@ }, { "internalType": "address", - "name": "originToken", + "name": "inputToken", "type": "address" }, { "internalType": "uint256", - "name": "amount", + "name": "inputAmount", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "outputAmount", "type": "uint256" }, { @@ -29,24 +34,29 @@ "type": "uint256" }, { - "internalType": "int64", - "name": "relayerFeePct", - "type": "int64" + "internalType": "address", + "name": "exclusiveRelayer", + "type": "address" }, { "internalType": "uint32", "name": "quoteTimestamp", "type": "uint32" }, + { + "internalType": "uint32", + "name": "fillDeadline", + "type": "uint32" + }, + { + "internalType": "uint32", + "name": "exclusivityDeadline", + "type": "uint32" + }, { "internalType": "bytes", "name": "message", "type": "bytes" - }, - { - "internalType": "uint256", - "name": "maxCount", - "type": "uint256" } ], "name": "deposit", @@ -55,59 +65,62 @@ "type": "function" } ], - "transactionHash": "0xbe91d2ea2fd20335b1f1a0ae1c7eca2e27970891d8b20897d25388633789006d", + "transactionHash": "0x1c82223bff2bcf2f4aa422493ff3044f5ab9a418e35f254d7ffb1d0494d7f65c", "receipt": { "to": "0x4e59b44847b379578588920cA78FbF26c0B4956C", "from": "0x9A8f92a830A5cB89a3816e3D267CB7791c16b04D", "contractAddress": null, - "transactionIndex": 76, - "gasUsed": "234906", - "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000008000000000000000000000000000000000000000000000000000000000800000000000000000000100020000000000000000000000000000000000000000000000000000000080000000040000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000004000000000000000800001000000000000000000000000000000100000000000000001000000000000000000000000000000000000000000000000000020100000", - "blockHash": "0x64e9d953783c9bc48f54010f84ff31474991784a020e7a773f41c2be131d1d94", - "transactionHash": "0xbe91d2ea2fd20335b1f1a0ae1c7eca2e27970891d8b20897d25388633789006d", + "transactionIndex": 23, + "gasUsed": "254525", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000800000000000000000000100000000000000000000000000000000000000000000000000000000000080000000040000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000004000800000000000800001000000008000000000000000000000100000000000000001020000000000000000000000000000000000000000000000000000100000", + "blockHash": "0x2f1b4487ef84859106ea91fa9d4f41e5e1cbae10c2a0509a262228ec662b6f42", + "transactionHash": "0x1c82223bff2bcf2f4aa422493ff3044f5ab9a418e35f254d7ffb1d0494d7f65c", "logs": [ { - "transactionIndex": 76, - "blockNumber": 55059424, - "transactionHash": "0xbe91d2ea2fd20335b1f1a0ae1c7eca2e27970891d8b20897d25388633789006d", + "transactionIndex": 23, + "blockNumber": 59840339, + "transactionHash": "0x1c82223bff2bcf2f4aa422493ff3044f5ab9a418e35f254d7ffb1d0494d7f65c", "address": "0x0000000000000000000000000000000000001010", "topics": [ "0x4dfe1bbbcf077ddc3e01291eea2d5c70c2b422b415d95645b9adcfd678cb1d63", "0x0000000000000000000000000000000000000000000000000000000000001010", "0x0000000000000000000000009a8f92a830a5cb89a3816e3d267cb7791c16b04d", - "0x000000000000000000000000794e44d1334a56fea7f4df12633b88820d0c5888" + "0x00000000000000000000000067b94473d81d0cd00849d563c94d0432ac988b49" ], - "data": "0x00000000000000000000000000000000000000000000000000191ab6464d2f86000000000000000000000000000000000000000000000002245b7befcea0cc4500000000000000000000000000000000000000000000001d6ebd97feb0c3479d0000000000000000000000000000000000000000000000022442613988539cbf00000000000000000000000000000000000000000000001d6ed6b2b4f7107723", - "logIndex": 304, - "blockHash": "0x64e9d953783c9bc48f54010f84ff31474991784a020e7a773f41c2be131d1d94" + "data": "0x000000000000000000000000000000000000000000000000001b20ac9657fc00000000000000000000000000000000000000000000000000dca62e4d8b541a5a0000000000000000000000000000000000000000000000ce493dcd2b344d28b5000000000000000000000000000000000000000000000000dc8b0da0f4fc1e5a0000000000000000000000000000000000000000000000ce4958edd7caa524b5", + "logIndex": 85, + "blockHash": "0x2f1b4487ef84859106ea91fa9d4f41e5e1cbae10c2a0509a262228ec662b6f42" } ], - "blockNumber": 55059424, - "cumulativeGasUsed": "9576285", + "blockNumber": 59840339, + "cumulativeGasUsed": "2786922", "status": 1, "byzantium": true }, "args": [], - "numDeployments": 3, - "solcInputHash": "53ab13385da43753d9a657e7780a0560", - "metadata": "{\"compiler\":{\"version\":\"0.8.19+commit.7dd6d404\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"contract SpokePoolInterface\",\"name\":\"spokePool\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"internalType\":\"int64\",\"name\":\"relayerFeePct\",\"type\":\"int64\"},{\"internalType\":\"uint32\",\"name\":\"quoteTimestamp\",\"type\":\"uint32\"},{\"internalType\":\"bytes\",\"name\":\"message\",\"type\":\"bytes\"},{\"internalType\":\"uint256\",\"name\":\"maxCount\",\"type\":\"uint256\"}],\"name\":\"deposit\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"This contract must be deployed via Create2 to the same address on all chains. That way, an errant transaction sent to the wrong chain will be blocked by this contract rather than hitting a dead address. This means that this contract will not work to protect chains, like zkSync, where Create2 address derivations don't match other chains. Source: https://era.zksync.io/docs/reference/architecture/differences-with-ethereum.html#create-create2\",\"kind\":\"dev\",\"methods\":{\"deposit(address,address,address,uint256,uint256,int64,uint32,bytes,uint256)\":{\"details\":\"Protects the caller from losing their ETH (or other native token) by reverting if the SpokePool address they intended to call does not exist on this chain. Because this contract can be deployed at the same address everywhere callers should be protected even if the transaction is submitted to an unintended network. This contract should only be used for native token deposits, as this problem only exists for native tokens.\",\"params\":{\"amount\":\"Amount of tokens to deposit. Will be amount of tokens to receive less fees.\",\"destinationChainId\":\"Denotes network where user will receive funds from SpokePool by a relayer.\",\"maxCount\":\"used to protect the depositor from frontrunning to guarantee their quote remains valid. Note: this is intended to be used to pass along instructions for how a contract should use or allocate the tokens.\",\"message\":\"Arbitrary data that can be used to pass additional information to the recipient along with the tokens. Note: this is intended to be used to pass along instructions for how a contract should use or allocate the tokens.\",\"originToken\":\"Token to lock into this contract to initiate deposit.\",\"quoteTimestamp\":\"Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid to LP pool on HubPool.\",\"recipient\":\"Address to receive funds at on destination chain.\",\"relayerFeePct\":\"% of deposit amount taken out to incentivize a fast relayer.\",\"spokePool\":\"Address of the SpokePool contract that the user is intending to call.\"}}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"deposit(address,address,address,uint256,uint256,int64,uint32,bytes,uint256)\":{\"notice\":\"Passthrough function to `depositV3()` on the SpokePool contract.\"}},\"notice\":\"SpokePoolVerifier is a contract that verifies that the SpokePool exists on this chain before sending ETH to it.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/SpokePoolVerifier.sol\":\"SpokePoolVerifier\"},\"debug\":{\"revertStrings\":\"strip\"},\"evmVersion\":\"paris\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":1000000},\"remappings\":[],\"viaIR\":true},\"sources\":{\"@openzeppelin/contracts/utils/Address.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.9.0) (utils/Address.sol)\\n\\npragma solidity ^0.8.1;\\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 * Furthermore, `isContract` will also return true if the target contract within\\n * the same transaction is already scheduled for destruction by `SELFDESTRUCT`,\\n * which only has an effect at the end of a transaction.\\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 > 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://consensys.net/diligence/blog/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.8.0/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\\n */\\n function sendValue(address payable recipient, uint256 amount) internal {\\n require(address(this).balance >= amount, \\\"Address: insufficient balance\\\");\\n\\n (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 functionCallWithValue(target, data, 0, \\\"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(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, value, \\\"Address: low-level call with value failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\\n * with `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(address(this).balance >= value, \\\"Address: insufficient balance for call\\\");\\n (bool success, bytes memory returndata) = target.call{value: value}(data);\\n return verifyCallResultFromTarget(target, 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 (bool success, bytes memory returndata) = target.staticcall(data);\\n return verifyCallResultFromTarget(target, 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 (bool success, bytes memory returndata) = target.delegatecall(data);\\n return verifyCallResultFromTarget(target, success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling\\n * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.\\n *\\n * _Available since v4.8._\\n */\\n function verifyCallResultFromTarget(\\n address target,\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n if (success) {\\n if (returndata.length == 0) {\\n // only check isContract if the call was successful and the return data is empty\\n // otherwise we already know that it was a contract\\n require(isContract(target), \\\"Address: call to non-contract\\\");\\n }\\n return returndata;\\n } else {\\n _revert(returndata, errorMessage);\\n }\\n }\\n\\n /**\\n * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the\\n * revert reason or 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 _revert(returndata, errorMessage);\\n }\\n }\\n\\n function _revert(bytes memory returndata, string memory errorMessage) private pure {\\n // Look for revert reason and bubble it up if present\\n if (returndata.length > 0) {\\n // The easiest way to bubble the revert reason is using memory via assembly\\n /// @solidity memory-safe-assembly\\n assembly {\\n let returndata_size := mload(returndata)\\n revert(add(32, returndata), returndata_size)\\n }\\n } else {\\n revert(errorMessage);\\n }\\n }\\n}\\n\",\"keccak256\":\"0x006dd67219697fe68d7fbfdea512e7c4cb64a43565ed86171d67e844982da6fa\",\"license\":\"MIT\"},\"contracts/SpokePoolVerifier.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\nimport \\\"@openzeppelin/contracts/utils/Address.sol\\\";\\nimport \\\"./interfaces/SpokePoolInterface.sol\\\";\\n\\n/**\\n * @notice SpokePoolVerifier is a contract that verifies that the SpokePool exists on this chain before sending ETH to it.\\n * @dev This contract must be deployed via Create2 to the same address on all chains. That way, an errant transaction sent\\n * to the wrong chain will be blocked by this contract rather than hitting a dead address. This means that this contract\\n * will not work to protect chains, like zkSync, where Create2 address derivations don't match other chains.\\n * Source: https://era.zksync.io/docs/reference/architecture/differences-with-ethereum.html#create-create2\\n */\\ncontract SpokePoolVerifier {\\n using Address for address;\\n\\n /**\\n * @notice Passthrough function to `depositV3()` on the SpokePool contract.\\n * @dev Protects the caller from losing their ETH (or other native token) by reverting if the SpokePool address\\n * they intended to call does not exist on this chain. Because this contract can be deployed at the same address\\n * everywhere callers should be protected even if the transaction is submitted to an unintended network.\\n * This contract should only be used for native token deposits, as this problem only exists for native tokens.\\n * @param spokePool Address of the SpokePool contract that the user is intending to call.\\n * @param recipient Address to receive funds at on destination chain.\\n * @param originToken Token to lock into this contract to initiate deposit.\\n * @param amount Amount of tokens to deposit. Will be amount of tokens to receive less fees.\\n * @param destinationChainId Denotes network where user will receive funds from SpokePool by a relayer.\\n * @param relayerFeePct % of deposit amount taken out to incentivize a fast relayer.\\n * @param quoteTimestamp Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid\\n * to LP pool on HubPool.\\n * @param message Arbitrary data that can be used to pass additional information to the recipient along with the tokens.\\n * Note: this is intended to be used to pass along instructions for how a contract should use or allocate the tokens.\\n * @param maxCount used to protect the depositor from frontrunning to guarantee their quote remains valid.\\n * Note: this is intended to be used to pass along instructions for how a contract should use or allocate the tokens.\\n */\\n function deposit(\\n SpokePoolInterface spokePool,\\n address recipient,\\n address originToken,\\n uint256 amount,\\n uint256 destinationChainId,\\n int64 relayerFeePct,\\n uint32 quoteTimestamp,\\n bytes memory message,\\n uint256 maxCount\\n ) external payable {\\n require(msg.value == amount, \\\"msg.value != amount\\\");\\n require(address(spokePool).isContract(), \\\"spokePool is not a contract\\\");\\n // Set msg.sender as the depositor so that msg.sender can speed up the deposit.\\n spokePool.depositFor{ value: msg.value }(\\n msg.sender,\\n recipient,\\n originToken,\\n amount,\\n destinationChainId,\\n relayerFeePct,\\n quoteTimestamp,\\n message,\\n maxCount\\n );\\n }\\n}\\n\",\"keccak256\":\"0xfc008c31a2fde7eb0daedaa823b76931225f41ac882b6d1c515d8a38ccda60ec\",\"license\":\"BUSL-1.1\"},\"contracts/interfaces/SpokePoolInterface.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\n/**\\n * @notice Contains common data structures and functions used by all SpokePool implementations.\\n */\\ninterface SpokePoolInterface {\\n // This leaf is meant to be decoded in the SpokePool to pay out successful relayers.\\n struct RelayerRefundLeaf {\\n // This is the amount to return to the HubPool. This occurs when there is a PoolRebalanceLeaf netSendAmount that\\n // is negative. This is just the negative of this value.\\n uint256 amountToReturn;\\n // Used to verify that this is being executed on the correct destination chainId.\\n uint256 chainId;\\n // This array designates how much each of those addresses should be refunded.\\n uint256[] refundAmounts;\\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\\n uint32 leafId;\\n // The associated L2TokenAddress that these claims apply to.\\n address l2TokenAddress;\\n // Must be same length as refundAmounts and designates each address that must be refunded.\\n address[] refundAddresses;\\n }\\n\\n // Stores collection of merkle roots that can be published to this contract from the HubPool, which are referenced\\n // by \\\"data workers\\\" via inclusion proofs to execute leaves in the roots.\\n struct RootBundle {\\n // Merkle root of slow relays that were not fully filled and whose recipient is still owed funds from the LP pool.\\n bytes32 slowRelayRoot;\\n // Merkle root of relayer refunds for successful relays.\\n bytes32 relayerRefundRoot;\\n // This is a 2D bitmap tracking which leaves in the relayer refund root have been claimed, with max size of\\n // 256x(2^248) leaves per root.\\n mapping(uint256 => uint256) claimedBitmap;\\n }\\n\\n function setCrossDomainAdmin(address newCrossDomainAdmin) external;\\n\\n function setHubPool(address newHubPool) external;\\n\\n function setEnableRoute(\\n address originToken,\\n uint256 destinationChainId,\\n bool enable\\n ) external;\\n\\n function pauseDeposits(bool pause) external;\\n\\n function pauseFills(bool pause) external;\\n\\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) external;\\n\\n function emergencyDeleteRootBundle(uint256 rootBundleId) external;\\n\\n function deposit(\\n address recipient,\\n address originToken,\\n uint256 amount,\\n uint256 destinationChainId,\\n int64 relayerFeePct,\\n uint32 quoteTimestamp,\\n bytes memory message,\\n uint256 maxCount\\n ) external payable;\\n\\n function depositFor(\\n address depositor,\\n address recipient,\\n address originToken,\\n uint256 amount,\\n uint256 destinationChainId,\\n int64 relayerFeePct,\\n uint32 quoteTimestamp,\\n bytes memory message,\\n uint256 maxCount\\n ) external payable;\\n\\n function executeRelayerRefundLeaf(\\n uint32 rootBundleId,\\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\\n bytes32[] memory proof\\n ) external payable;\\n\\n function chainId() external view returns (uint256);\\n\\n error NotEOA();\\n error InvalidDepositorSignature();\\n error InvalidRelayerFeePct();\\n error MaxTransferSizeExceeded();\\n error InvalidCrossDomainAdmin();\\n error InvalidHubPool();\\n error DepositsArePaused();\\n error FillsArePaused();\\n}\\n\",\"keccak256\":\"0xc90fbd7e66e2e87e9aacbe93c20cc020cd1fc582c4fd4879807e7dc026943ea0\",\"license\":\"BUSL-1.1\"}},\"version\":1}", - "bytecode": "0x608080604052346100165761034b908161001c8239f35b600080fdfe600436101561000d57600080fd5b6000803560e01c63e0db3fcf1461002357600080fd5b610120807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103115773ffffffffffffffffffffffffffffffffffffffff600435818116810361030d576024359282841684036103095760443583811681036103055760a4358060070b81036103015760c4359063ffffffff8216820361029b5760e43567ffffffffffffffff81116102fd57366023820112156102fd57806004013567ffffffffffffffff81116102d0577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0603f81601f84011601166080016080811067ffffffffffffffff8211176102a357908a929160405280608052366024828401011161029f57602091819060240160a0376080010152606435340361029b578585163b1561029b578585163b1561029b57859694929163ffffffff91878a9896946040519a8b997f541f4f14000000000000000000000000000000000000000000000000000000008b523360048c01521660248a01521660448801526064356064880152608435608488015260070b60a48701521660c485015260e484015260805180610124850152845b8181106102805750908391827fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f6101449389858286010152610104803590850152011681010301923491165af1801561027557610233575080f35b67ffffffffffffffff81116102485760405280f35b6024827f4e487b710000000000000000000000000000000000000000000000000000000081526041600452fd5b6040513d84823e3d90fd5b60a081015187820161014401528795508694506020016101d6565b8780fd5b8280fd5b60248b7f4e487b710000000000000000000000000000000000000000000000000000000081526041600452fd5b60248a7f4e487b710000000000000000000000000000000000000000000000000000000081526041600452fd5b8880fd5b8680fd5b8580fd5b8480fd5b8380fd5b5080fdfea26469706673582212204f81f550f00970671d0755020f959a6599fd76306000e67b424172e1089b949a64736f6c63430008130033", - "deployedBytecode": "0x600436101561000d57600080fd5b6000803560e01c63e0db3fcf1461002357600080fd5b610120807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103115773ffffffffffffffffffffffffffffffffffffffff600435818116810361030d576024359282841684036103095760443583811681036103055760a4358060070b81036103015760c4359063ffffffff8216820361029b5760e43567ffffffffffffffff81116102fd57366023820112156102fd57806004013567ffffffffffffffff81116102d0577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0603f81601f84011601166080016080811067ffffffffffffffff8211176102a357908a929160405280608052366024828401011161029f57602091819060240160a0376080010152606435340361029b578585163b1561029b578585163b1561029b57859694929163ffffffff91878a9896946040519a8b997f541f4f14000000000000000000000000000000000000000000000000000000008b523360048c01521660248a01521660448801526064356064880152608435608488015260070b60a48701521660c485015260e484015260805180610124850152845b8181106102805750908391827fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f6101449389858286010152610104803590850152011681010301923491165af1801561027557610233575080f35b67ffffffffffffffff81116102485760405280f35b6024827f4e487b710000000000000000000000000000000000000000000000000000000081526041600452fd5b6040513d84823e3d90fd5b60a081015187820161014401528795508694506020016101d6565b8780fd5b8280fd5b60248b7f4e487b710000000000000000000000000000000000000000000000000000000081526041600452fd5b60248a7f4e487b710000000000000000000000000000000000000000000000000000000081526041600452fd5b8880fd5b8680fd5b8580fd5b8480fd5b8380fd5b5080fdfea26469706673582212204f81f550f00970671d0755020f959a6599fd76306000e67b424172e1089b949a64736f6c63430008130033", + "numDeployments": 5, + "solcInputHash": "783274f805324492b21545b62eb0dbfe", + "metadata": "{\"compiler\":{\"version\":\"0.8.19+commit.7dd6d404\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"contract V3SpokePoolInterface\",\"name\":\"spokePool\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"inputToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"inputAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"outputAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"exclusiveRelayer\",\"type\":\"address\"},{\"internalType\":\"uint32\",\"name\":\"quoteTimestamp\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"fillDeadline\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"exclusivityDeadline\",\"type\":\"uint32\"},{\"internalType\":\"bytes\",\"name\":\"message\",\"type\":\"bytes\"}],\"name\":\"deposit\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"}],\"devdoc\":{\"custom:security-contact\":\"bugs@across.to\",\"details\":\"This contract must be deployed via Create2 to the same address on all chains. That way, an errant transaction sent to the wrong chain will be blocked by this contract rather than hitting a dead address. This means that this contract will not work to protect chains, like zkSync, where Create2 address derivations don't match other chains. Source: https://era.zksync.io/docs/reference/architecture/differences-with-ethereum.html#create-create2\",\"kind\":\"dev\",\"methods\":{\"deposit(address,address,address,uint256,uint256,uint256,address,uint32,uint32,uint32,bytes)\":{\"details\":\"Protects the caller from losing their ETH (or other native token) by reverting if the SpokePool address they intended to call does not exist on this chain. Because this contract can be deployed at the same address everywhere callers should be protected even if the transaction is submitted to an unintended network. This contract should only be used for native token deposits, as this problem only exists for native tokens.\",\"params\":{\"destinationChainId\":\"Denotes network where user will receive funds from SpokePool by a relayer.\",\"exclusiveRelayer\":\"Address of the relayer who has exclusive rights to fill this deposit. Can be set to 0x0 if no exclusivity period is desired. If so, then must set exclusivityDeadline to 0.\",\"exclusivityDeadline\":\"Timestamp after which any relayer can fill this deposit. Must set to 0 if exclusiveRelayer is set to 0x0, and vice versa.\",\"fillDeadline\":\"Timestamp after which this deposit can no longer be filled.\",\"inputAmount\":\"Amount of tokens to deposit.\",\"inputToken\":\"Token to lock into this contract to initiate deposit.\",\"message\":\"Arbitrary data that can be used to pass additional information to the recipient along with the tokens. Note: this is intended to be used to pass along instructions for how a contract should use or allocate the tokens.\",\"outputAmount\":\"Amount of tokens to receive on destination chain.\",\"quoteTimestamp\":\"Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid to LP pool on HubPool.\",\"recipient\":\"Address to receive funds at on destination chain.\",\"spokePool\":\"Address of the SpokePool contract that the user is intending to call.\"}}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"deposit(address,address,address,uint256,uint256,uint256,address,uint32,uint32,uint32,bytes)\":{\"notice\":\"Passthrough function to `depositV3()` on the SpokePool contract.\"}},\"notice\":\"SpokePoolVerifier is a contract that verifies that the SpokePool exists on this chain before sending ETH to it.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/SpokePoolVerifier.sol\":\"SpokePoolVerifier\"},\"debug\":{\"revertStrings\":\"strip\"},\"evmVersion\":\"paris\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":1000000},\"remappings\":[],\"viaIR\":true},\"sources\":{\"@openzeppelin/contracts/utils/Address.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.9.0) (utils/Address.sol)\\n\\npragma solidity ^0.8.1;\\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 * Furthermore, `isContract` will also return true if the target contract within\\n * the same transaction is already scheduled for destruction by `SELFDESTRUCT`,\\n * which only has an effect at the end of a transaction.\\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 > 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://consensys.net/diligence/blog/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.8.0/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\\n */\\n function sendValue(address payable recipient, uint256 amount) internal {\\n require(address(this).balance >= amount, \\\"Address: insufficient balance\\\");\\n\\n (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 functionCallWithValue(target, data, 0, \\\"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(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, value, \\\"Address: low-level call with value failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\\n * with `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(address(this).balance >= value, \\\"Address: insufficient balance for call\\\");\\n (bool success, bytes memory returndata) = target.call{value: value}(data);\\n return verifyCallResultFromTarget(target, 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 (bool success, bytes memory returndata) = target.staticcall(data);\\n return verifyCallResultFromTarget(target, 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 (bool success, bytes memory returndata) = target.delegatecall(data);\\n return verifyCallResultFromTarget(target, success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling\\n * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.\\n *\\n * _Available since v4.8._\\n */\\n function verifyCallResultFromTarget(\\n address target,\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n if (success) {\\n if (returndata.length == 0) {\\n // only check isContract if the call was successful and the return data is empty\\n // otherwise we already know that it was a contract\\n require(isContract(target), \\\"Address: call to non-contract\\\");\\n }\\n return returndata;\\n } else {\\n _revert(returndata, errorMessage);\\n }\\n }\\n\\n /**\\n * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the\\n * revert reason or 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 _revert(returndata, errorMessage);\\n }\\n }\\n\\n function _revert(bytes memory returndata, string memory errorMessage) private pure {\\n // Look for revert reason and bubble it up if present\\n if (returndata.length > 0) {\\n // The easiest way to bubble the revert reason is using memory via assembly\\n /// @solidity memory-safe-assembly\\n assembly {\\n let returndata_size := mload(returndata)\\n revert(add(32, returndata), returndata_size)\\n }\\n } else {\\n revert(errorMessage);\\n }\\n }\\n}\\n\",\"keccak256\":\"0x006dd67219697fe68d7fbfdea512e7c4cb64a43565ed86171d67e844982da6fa\",\"license\":\"MIT\"},\"contracts/SpokePoolVerifier.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\nimport \\\"@openzeppelin/contracts/utils/Address.sol\\\";\\nimport \\\"./interfaces/V3SpokePoolInterface.sol\\\";\\n\\n/**\\n * @notice SpokePoolVerifier is a contract that verifies that the SpokePool exists on this chain before sending ETH to it.\\n * @dev This contract must be deployed via Create2 to the same address on all chains. That way, an errant transaction sent\\n * to the wrong chain will be blocked by this contract rather than hitting a dead address. This means that this contract\\n * will not work to protect chains, like zkSync, where Create2 address derivations don't match other chains.\\n * Source: https://era.zksync.io/docs/reference/architecture/differences-with-ethereum.html#create-create2\\n * @custom:security-contact bugs@across.to\\n */\\ncontract SpokePoolVerifier {\\n using Address for address;\\n\\n /**\\n * @notice Passthrough function to `depositV3()` on the SpokePool contract.\\n * @dev Protects the caller from losing their ETH (or other native token) by reverting if the SpokePool address\\n * they intended to call does not exist on this chain. Because this contract can be deployed at the same address\\n * everywhere callers should be protected even if the transaction is submitted to an unintended network.\\n * This contract should only be used for native token deposits, as this problem only exists for native tokens.\\n * @param spokePool Address of the SpokePool contract that the user is intending to call.\\n * @param recipient Address to receive funds at on destination chain.\\n * @param inputToken Token to lock into this contract to initiate deposit.\\n * @param inputAmount Amount of tokens to deposit.\\n * @param outputAmount Amount of tokens to receive on destination chain.\\n * @param destinationChainId Denotes network where user will receive funds from SpokePool by a relayer.\\n * @param quoteTimestamp Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid\\n * to LP pool on HubPool.\\n * @param message Arbitrary data that can be used to pass additional information to the recipient along with the tokens.\\n * Note: this is intended to be used to pass along instructions for how a contract should use or allocate the tokens.\\n * @param exclusiveRelayer Address of the relayer who has exclusive rights to fill this deposit. Can be set to\\n * 0x0 if no exclusivity period is desired. If so, then must set exclusivityDeadline to 0.\\n * @param exclusivityDeadline Timestamp after which any relayer can fill this deposit. Must set\\n * to 0 if exclusiveRelayer is set to 0x0, and vice versa.\\n * @param fillDeadline Timestamp after which this deposit can no longer be filled.\\n */\\n function deposit(\\n V3SpokePoolInterface spokePool,\\n address recipient,\\n address inputToken,\\n uint256 inputAmount,\\n uint256 outputAmount,\\n uint256 destinationChainId,\\n address exclusiveRelayer,\\n uint32 quoteTimestamp,\\n uint32 fillDeadline,\\n uint32 exclusivityDeadline,\\n bytes memory message\\n ) external payable {\\n require(msg.value == inputAmount, \\\"msg.value != amount\\\");\\n require(address(spokePool).isContract(), \\\"spokePool is not a contract\\\");\\n // Set msg.sender as the depositor so that msg.sender can speed up the deposit.\\n spokePool.depositV3{ value: msg.value }(\\n msg.sender,\\n recipient,\\n inputToken,\\n // @dev Setting outputToken to 0x0 to instruct fillers to use the equivalent token\\n // as the originToken on the destination chain.\\n address(0),\\n inputAmount,\\n outputAmount,\\n destinationChainId,\\n exclusiveRelayer,\\n quoteTimestamp,\\n fillDeadline,\\n exclusivityDeadline,\\n message\\n );\\n }\\n}\\n\",\"keccak256\":\"0xd5b1ec1b7048634a8b0a7e1e2c68ce51e410157b14778a207b64aff49bc5c6f0\",\"license\":\"BUSL-1.1\"},\"contracts/interfaces/V3SpokePoolInterface.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\n// Contains structs and functions used by SpokePool contracts to facilitate universal settlement.\\ninterface V3SpokePoolInterface {\\n /**************************************\\n * ENUMS *\\n **************************************/\\n\\n // Fill status tracks on-chain state of deposit, uniquely identified by relayHash.\\n enum FillStatus {\\n Unfilled,\\n RequestedSlowFill,\\n Filled\\n }\\n // Fill type is emitted in the FilledRelay event to assist Dataworker with determining which types of\\n // fills to refund (e.g. only fast fills) and whether a fast fill created a sow fill excess.\\n enum FillType {\\n FastFill,\\n // Fast fills are normal fills that do not replace a slow fill request.\\n ReplacedSlowFill,\\n // Replaced slow fills are fast fills that replace a slow fill request. This type is used by the Dataworker\\n // to know when to send excess funds from the SpokePool to the HubPool because they can no longer be used\\n // for a slow fill execution.\\n SlowFill\\n // Slow fills are requested via requestSlowFill and executed by executeSlowRelayLeaf after a bundle containing\\n // the slow fill is validated.\\n }\\n\\n /**************************************\\n * STRUCTS *\\n **************************************/\\n\\n // This struct represents the data to fully specify a **unique** relay submitted on this chain.\\n // This data is hashed with the chainId() and saved by the SpokePool to prevent collisions and protect against\\n // replay attacks on other chains. If any portion of this data differs, the relay is considered to be\\n // completely distinct.\\n struct V3RelayData {\\n // The address that made the deposit on the origin chain.\\n address depositor;\\n // The recipient address on the destination chain.\\n address recipient;\\n // This is the exclusive relayer who can fill the deposit before the exclusivity deadline.\\n address exclusiveRelayer;\\n // Token that is deposited on origin chain by depositor.\\n address inputToken;\\n // Token that is received on destination chain by recipient.\\n address outputToken;\\n // The amount of input token deposited by depositor.\\n uint256 inputAmount;\\n // The amount of output token to be received by recipient.\\n uint256 outputAmount;\\n // Origin chain id.\\n uint256 originChainId;\\n // The id uniquely identifying this deposit on the origin chain.\\n uint32 depositId;\\n // The timestamp on the destination chain after which this deposit can no longer be filled.\\n uint32 fillDeadline;\\n // The timestamp on the destination chain after which any relayer can fill the deposit.\\n uint32 exclusivityDeadline;\\n // Data that is forwarded to the recipient.\\n bytes message;\\n }\\n\\n // Contains parameters passed in by someone who wants to execute a slow relay leaf.\\n struct V3SlowFill {\\n V3RelayData relayData;\\n uint256 chainId;\\n uint256 updatedOutputAmount;\\n }\\n\\n // Contains information about a relay to be sent along with additional information that is not unique to the\\n // relay itself but is required to know how to process the relay. For example, \\\"updatedX\\\" fields can be used\\n // by the relayer to modify fields of the relay with the depositor's permission, and \\\"repaymentChainId\\\" is specified\\n // by the relayer to determine where to take a relayer refund, but doesn't affect the uniqueness of the relay.\\n struct V3RelayExecutionParams {\\n V3RelayData relay;\\n bytes32 relayHash;\\n uint256 updatedOutputAmount;\\n address updatedRecipient;\\n bytes updatedMessage;\\n uint256 repaymentChainId;\\n }\\n\\n // Packs together parameters emitted in FilledV3Relay because there are too many emitted otherwise.\\n // Similar to V3RelayExecutionParams, these parameters are not used to uniquely identify the deposit being\\n // filled so they don't have to be unpacked by all clients.\\n struct V3RelayExecutionEventInfo {\\n address updatedRecipient;\\n bytes updatedMessage;\\n uint256 updatedOutputAmount;\\n FillType fillType;\\n }\\n\\n /**************************************\\n * EVENTS *\\n **************************************/\\n\\n event V3FundsDeposited(\\n address inputToken,\\n address outputToken,\\n uint256 inputAmount,\\n uint256 outputAmount,\\n uint256 indexed destinationChainId,\\n uint32 indexed depositId,\\n uint32 quoteTimestamp,\\n uint32 fillDeadline,\\n uint32 exclusivityDeadline,\\n address indexed depositor,\\n address recipient,\\n address exclusiveRelayer,\\n bytes message\\n );\\n\\n event RequestedSpeedUpV3Deposit(\\n uint256 updatedOutputAmount,\\n uint32 indexed depositId,\\n address indexed depositor,\\n address updatedRecipient,\\n bytes updatedMessage,\\n bytes depositorSignature\\n );\\n\\n event FilledV3Relay(\\n address inputToken,\\n address outputToken,\\n uint256 inputAmount,\\n uint256 outputAmount,\\n uint256 repaymentChainId,\\n uint256 indexed originChainId,\\n uint32 indexed depositId,\\n uint32 fillDeadline,\\n uint32 exclusivityDeadline,\\n address exclusiveRelayer,\\n address indexed relayer,\\n address depositor,\\n address recipient,\\n bytes message,\\n V3RelayExecutionEventInfo relayExecutionInfo\\n );\\n\\n event RequestedV3SlowFill(\\n address inputToken,\\n address outputToken,\\n uint256 inputAmount,\\n uint256 outputAmount,\\n uint256 indexed originChainId,\\n uint32 indexed depositId,\\n uint32 fillDeadline,\\n uint32 exclusivityDeadline,\\n address exclusiveRelayer,\\n address depositor,\\n address recipient,\\n bytes message\\n );\\n\\n /**************************************\\n * FUNCTIONS *\\n **************************************/\\n\\n function depositV3(\\n address depositor,\\n address recipient,\\n address inputToken,\\n address outputToken,\\n uint256 inputAmount,\\n uint256 outputAmount,\\n uint256 destinationChainId,\\n address exclusiveRelayer,\\n uint32 quoteTimestamp,\\n uint32 fillDeadline,\\n uint32 exclusivityDeadline,\\n bytes calldata message\\n ) external payable;\\n\\n function depositV3Now(\\n address depositor,\\n address recipient,\\n address inputToken,\\n address outputToken,\\n uint256 inputAmount,\\n uint256 outputAmount,\\n uint256 destinationChainId,\\n address exclusiveRelayer,\\n uint32 fillDeadlineOffset,\\n uint32 exclusivityDeadline,\\n bytes calldata message\\n ) external payable;\\n\\n function speedUpV3Deposit(\\n address depositor,\\n uint32 depositId,\\n uint256 updatedOutputAmount,\\n address updatedRecipient,\\n bytes calldata updatedMessage,\\n bytes calldata depositorSignature\\n ) external;\\n\\n function fillV3Relay(V3RelayData calldata relayData, uint256 repaymentChainId) external;\\n\\n function fillV3RelayWithUpdatedDeposit(\\n V3RelayData calldata relayData,\\n uint256 repaymentChainId,\\n uint256 updatedOutputAmount,\\n address updatedRecipient,\\n bytes calldata updatedMessage,\\n bytes calldata depositorSignature\\n ) external;\\n\\n function requestV3SlowFill(V3RelayData calldata relayData) external;\\n\\n function executeV3SlowRelayLeaf(\\n V3SlowFill calldata slowFillLeaf,\\n uint32 rootBundleId,\\n bytes32[] calldata proof\\n ) external;\\n\\n /**************************************\\n * ERRORS *\\n **************************************/\\n\\n error DisabledRoute();\\n error InvalidQuoteTimestamp();\\n error InvalidFillDeadline();\\n error InvalidExclusiveRelayer();\\n error InvalidExclusivityDeadline();\\n error MsgValueDoesNotMatchInputAmount();\\n error NotExclusiveRelayer();\\n error NoSlowFillsInExclusivityWindow();\\n error RelayFilled();\\n error InvalidSlowFillRequest();\\n error ExpiredFillDeadline();\\n error InvalidMerkleProof();\\n error InvalidChainId();\\n error InvalidMerkleLeaf();\\n error ClaimedMerkleLeaf();\\n error InvalidPayoutAdjustmentPct();\\n}\\n\",\"keccak256\":\"0x374b7e9cb8afbcaec69cdbcde480676b5d927db84c7f38221331d1226af68d9d\",\"license\":\"BUSL-1.1\"}},\"version\":1}", + "bytecode": "0x60808060405234610016576103a4908161001c8239f35b600080fdfe600436101561000d57600080fd5b6000803560e01c63902e949c1461002357600080fd5b6101607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261036b5773ffffffffffffffffffffffffffffffffffffffff6004358181168103610367576024359082821682036103635760443591838316830361035f5760c435848116810361035b5760e4359063ffffffff928383168303610357576101043590848216820361035357610124359385851685036103225767ffffffffffffffff610144351161032257366023610144350112156103225767ffffffffffffffff6101443560040135116103265767ffffffffffffffff6004610144350135601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f0116608090810191821191101761032657608060046101443590810135601f81017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f011683016040529182905236910160240111610322576101443560048101359060240160a03760a06004610144350135018a90526064353403610322578887163b15610322578887163b1561032257918589979593888296818e9c60409e9b979e519e8f9d8e917f7b9392320000000000000000000000000000000000000000000000000000000083523360048401521690602401521660448c01528b60648c015260643560848c015260843560a48c015260a43560c48c01521660e48a01521661010488015216610124860152166101448401526101648301610180905260805180610184850152845b8181106103075750908391827fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f6101a49389858286010152011681010301923491165af180156102fc576102ba575080f35b67ffffffffffffffff81116102cf5760405280f35b6024827f4e487b710000000000000000000000000000000000000000000000000000000081526041600452fd5b6040513d84823e3d90fd5b60a08101518782016101a40152879550869450602001610266565b8980fd5b60248a7f4e487b710000000000000000000000000000000000000000000000000000000081526041600452fd5b8880fd5b8780fd5b8580fd5b8480fd5b8380fd5b8280fd5b80fdfea26469706673582212201ceff237e6adbd0d3f92e892f7f3f51306c23eac5f7e3f896c2c723d9e5be3a664736f6c63430008130033", + "deployedBytecode": "0x600436101561000d57600080fd5b6000803560e01c63902e949c1461002357600080fd5b6101607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261036b5773ffffffffffffffffffffffffffffffffffffffff6004358181168103610367576024359082821682036103635760443591838316830361035f5760c435848116810361035b5760e4359063ffffffff928383168303610357576101043590848216820361035357610124359385851685036103225767ffffffffffffffff610144351161032257366023610144350112156103225767ffffffffffffffff6101443560040135116103265767ffffffffffffffff6004610144350135601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f0116608090810191821191101761032657608060046101443590810135601f81017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f011683016040529182905236910160240111610322576101443560048101359060240160a03760a06004610144350135018a90526064353403610322578887163b15610322578887163b1561032257918589979593888296818e9c60409e9b979e519e8f9d8e917f7b9392320000000000000000000000000000000000000000000000000000000083523360048401521690602401521660448c01528b60648c015260643560848c015260843560a48c015260a43560c48c01521660e48a01521661010488015216610124860152166101448401526101648301610180905260805180610184850152845b8181106103075750908391827fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f6101a49389858286010152011681010301923491165af180156102fc576102ba575080f35b67ffffffffffffffff81116102cf5760405280f35b6024827f4e487b710000000000000000000000000000000000000000000000000000000081526041600452fd5b6040513d84823e3d90fd5b60a08101518782016101a40152879550869450602001610266565b8980fd5b60248a7f4e487b710000000000000000000000000000000000000000000000000000000081526041600452fd5b8880fd5b8780fd5b8580fd5b8480fd5b8380fd5b8280fd5b80fdfea26469706673582212201ceff237e6adbd0d3f92e892f7f3f51306c23eac5f7e3f896c2c723d9e5be3a664736f6c63430008130033", "devdoc": { + "custom:security-contact": "bugs@across.to", "details": "This contract must be deployed via Create2 to the same address on all chains. That way, an errant transaction sent to the wrong chain will be blocked by this contract rather than hitting a dead address. This means that this contract will not work to protect chains, like zkSync, where Create2 address derivations don't match other chains. Source: https://era.zksync.io/docs/reference/architecture/differences-with-ethereum.html#create-create2", "kind": "dev", "methods": { - "deposit(address,address,address,uint256,uint256,int64,uint32,bytes,uint256)": { + "deposit(address,address,address,uint256,uint256,uint256,address,uint32,uint32,uint32,bytes)": { "details": "Protects the caller from losing their ETH (or other native token) by reverting if the SpokePool address they intended to call does not exist on this chain. Because this contract can be deployed at the same address everywhere callers should be protected even if the transaction is submitted to an unintended network. This contract should only be used for native token deposits, as this problem only exists for native tokens.", "params": { - "amount": "Amount of tokens to deposit. Will be amount of tokens to receive less fees.", "destinationChainId": "Denotes network where user will receive funds from SpokePool by a relayer.", - "maxCount": "used to protect the depositor from frontrunning to guarantee their quote remains valid. Note: this is intended to be used to pass along instructions for how a contract should use or allocate the tokens.", + "exclusiveRelayer": "Address of the relayer who has exclusive rights to fill this deposit. Can be set to 0x0 if no exclusivity period is desired. If so, then must set exclusivityDeadline to 0.", + "exclusivityDeadline": "Timestamp after which any relayer can fill this deposit. Must set to 0 if exclusiveRelayer is set to 0x0, and vice versa.", + "fillDeadline": "Timestamp after which this deposit can no longer be filled.", + "inputAmount": "Amount of tokens to deposit.", + "inputToken": "Token to lock into this contract to initiate deposit.", "message": "Arbitrary data that can be used to pass additional information to the recipient along with the tokens. Note: this is intended to be used to pass along instructions for how a contract should use or allocate the tokens.", - "originToken": "Token to lock into this contract to initiate deposit.", + "outputAmount": "Amount of tokens to receive on destination chain.", "quoteTimestamp": "Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid to LP pool on HubPool.", "recipient": "Address to receive funds at on destination chain.", - "relayerFeePct": "% of deposit amount taken out to incentivize a fast relayer.", "spokePool": "Address of the SpokePool contract that the user is intending to call." } } @@ -117,7 +130,7 @@ "userdoc": { "kind": "user", "methods": { - "deposit(address,address,address,uint256,uint256,int64,uint32,bytes,uint256)": { + "deposit(address,address,address,uint256,uint256,uint256,address,uint32,uint32,uint32,bytes)": { "notice": "Passthrough function to `depositV3()` on the SpokePool contract." } }, diff --git a/deployments/polygon/solcInputs/1a67233dfe969c05446730f26ab1d2c8.json b/deployments/polygon/solcInputs/1a67233dfe969c05446730f26ab1d2c8.json new file mode 100644 index 000000000..96daeb1aa --- /dev/null +++ b/deployments/polygon/solcInputs/1a67233dfe969c05446730f26ab1d2c8.json @@ -0,0 +1,43 @@ +{ + "language": "Solidity", + "sources": { + "@openzeppelin/contracts/utils/Address.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (utils/Address.sol)\n\npragma solidity ^0.8.1;\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 * Furthermore, `isContract` will also return true if the target contract within\n * the same transaction is already scheduled for destruction by `SELFDESTRUCT`,\n * which only has an effect at the end of a transaction.\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 > 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://consensys.net/diligence/blog/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.8.0/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n require(address(this).balance >= amount, \"Address: insufficient balance\");\n\n (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 functionCallWithValue(target, data, 0, \"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(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n return functionCallWithValue(target, data, value, \"Address: low-level call with value failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\n * with `errorMessage` as a fallback revert reason when `target` reverts.\n *\n * _Available since v3.1._\n */\n function functionCallWithValue(\n address target,\n bytes memory data,\n uint256 value,\n string memory errorMessage\n ) internal returns (bytes memory) {\n require(address(this).balance >= value, \"Address: insufficient balance for call\");\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, 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 (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, 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 (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata, errorMessage);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling\n * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.\n *\n * _Available since v4.8._\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata,\n string memory errorMessage\n ) internal view returns (bytes memory) {\n if (success) {\n if (returndata.length == 0) {\n // only check isContract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n require(isContract(target), \"Address: call to non-contract\");\n }\n return returndata;\n } else {\n _revert(returndata, errorMessage);\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the\n * revert reason or 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 _revert(returndata, errorMessage);\n }\n }\n\n function _revert(bytes memory returndata, string memory errorMessage) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length > 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert(errorMessage);\n }\n }\n}\n" + }, + "contracts/interfaces/V3SpokePoolInterface.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n// Contains structs and functions used by SpokePool contracts to facilitate universal settlement.\ninterface V3SpokePoolInterface {\n /**************************************\n * ENUMS *\n **************************************/\n\n // Fill status tracks on-chain state of deposit, uniquely identified by relayHash.\n enum FillStatus {\n Unfilled,\n RequestedSlowFill,\n Filled\n }\n // Fill type is emitted in the FilledRelay event to assist Dataworker with determining which types of\n // fills to refund (e.g. only fast fills) and whether a fast fill created a sow fill excess.\n enum FillType {\n FastFill,\n // Fast fills are normal fills that do not replace a slow fill request.\n ReplacedSlowFill,\n // Replaced slow fills are fast fills that replace a slow fill request. This type is used by the Dataworker\n // to know when to send excess funds from the SpokePool to the HubPool because they can no longer be used\n // for a slow fill execution.\n SlowFill\n // Slow fills are requested via requestSlowFill and executed by executeSlowRelayLeaf after a bundle containing\n // the slow fill is validated.\n }\n\n /**************************************\n * STRUCTS *\n **************************************/\n\n // This struct represents the data to fully specify a **unique** relay submitted on this chain.\n // This data is hashed with the chainId() and saved by the SpokePool to prevent collisions and protect against\n // replay attacks on other chains. If any portion of this data differs, the relay is considered to be\n // completely distinct.\n struct V3RelayData {\n // The address that made the deposit on the origin chain.\n address depositor;\n // The recipient address on the destination chain.\n address recipient;\n // This is the exclusive relayer who can fill the deposit before the exclusivity deadline.\n address exclusiveRelayer;\n // Token that is deposited on origin chain by depositor.\n address inputToken;\n // Token that is received on destination chain by recipient.\n address outputToken;\n // The amount of input token deposited by depositor.\n uint256 inputAmount;\n // The amount of output token to be received by recipient.\n uint256 outputAmount;\n // Origin chain id.\n uint256 originChainId;\n // The id uniquely identifying this deposit on the origin chain.\n uint32 depositId;\n // The timestamp on the destination chain after which this deposit can no longer be filled.\n uint32 fillDeadline;\n // The timestamp on the destination chain after which any relayer can fill the deposit.\n uint32 exclusivityDeadline;\n // Data that is forwarded to the recipient.\n bytes message;\n }\n\n // Contains parameters passed in by someone who wants to execute a slow relay leaf.\n struct V3SlowFill {\n V3RelayData relayData;\n uint256 chainId;\n uint256 updatedOutputAmount;\n }\n\n // Contains information about a relay to be sent along with additional information that is not unique to the\n // relay itself but is required to know how to process the relay. For example, \"updatedX\" fields can be used\n // by the relayer to modify fields of the relay with the depositor's permission, and \"repaymentChainId\" is specified\n // by the relayer to determine where to take a relayer refund, but doesn't affect the uniqueness of the relay.\n struct V3RelayExecutionParams {\n V3RelayData relay;\n bytes32 relayHash;\n uint256 updatedOutputAmount;\n address updatedRecipient;\n bytes updatedMessage;\n uint256 repaymentChainId;\n }\n\n // Packs together parameters emitted in FilledV3Relay because there are too many emitted otherwise.\n // Similar to V3RelayExecutionParams, these parameters are not used to uniquely identify the deposit being\n // filled so they don't have to be unpacked by all clients.\n struct V3RelayExecutionEventInfo {\n address updatedRecipient;\n bytes updatedMessage;\n uint256 updatedOutputAmount;\n FillType fillType;\n }\n\n /**************************************\n * EVENTS *\n **************************************/\n\n event V3FundsDeposited(\n address inputToken,\n address outputToken,\n uint256 inputAmount,\n uint256 outputAmount,\n uint256 indexed destinationChainId,\n uint32 indexed depositId,\n uint32 quoteTimestamp,\n uint32 fillDeadline,\n uint32 exclusivityDeadline,\n address indexed depositor,\n address recipient,\n address exclusiveRelayer,\n bytes message\n );\n\n event RequestedSpeedUpV3Deposit(\n uint256 updatedOutputAmount,\n uint32 indexed depositId,\n address indexed depositor,\n address updatedRecipient,\n bytes updatedMessage,\n bytes depositorSignature\n );\n\n event FilledV3Relay(\n address inputToken,\n address outputToken,\n uint256 inputAmount,\n uint256 outputAmount,\n uint256 repaymentChainId,\n uint256 indexed originChainId,\n uint32 indexed depositId,\n uint32 fillDeadline,\n uint32 exclusivityDeadline,\n address exclusiveRelayer,\n address indexed relayer,\n address depositor,\n address recipient,\n bytes message,\n V3RelayExecutionEventInfo relayExecutionInfo\n );\n\n event RequestedV3SlowFill(\n address inputToken,\n address outputToken,\n uint256 inputAmount,\n uint256 outputAmount,\n uint256 indexed originChainId,\n uint32 indexed depositId,\n uint32 fillDeadline,\n uint32 exclusivityDeadline,\n address exclusiveRelayer,\n address depositor,\n address recipient,\n bytes message\n );\n\n /**************************************\n * FUNCTIONS *\n **************************************/\n\n function depositV3(\n address depositor,\n address recipient,\n address inputToken,\n address outputToken,\n uint256 inputAmount,\n uint256 outputAmount,\n uint256 destinationChainId,\n address exclusiveRelayer,\n uint32 quoteTimestamp,\n uint32 fillDeadline,\n uint32 exclusivityDeadline,\n bytes calldata message\n ) external payable;\n\n function depositV3Now(\n address depositor,\n address recipient,\n address inputToken,\n address outputToken,\n uint256 inputAmount,\n uint256 outputAmount,\n uint256 destinationChainId,\n address exclusiveRelayer,\n uint32 fillDeadlineOffset,\n uint32 exclusivityDeadline,\n bytes calldata message\n ) external payable;\n\n function speedUpV3Deposit(\n address depositor,\n uint32 depositId,\n uint256 updatedOutputAmount,\n address updatedRecipient,\n bytes calldata updatedMessage,\n bytes calldata depositorSignature\n ) external;\n\n function fillV3Relay(V3RelayData calldata relayData, uint256 repaymentChainId) external;\n\n function fillV3RelayWithUpdatedDeposit(\n V3RelayData calldata relayData,\n uint256 repaymentChainId,\n uint256 updatedOutputAmount,\n address updatedRecipient,\n bytes calldata updatedMessage,\n bytes calldata depositorSignature\n ) external;\n\n function requestV3SlowFill(V3RelayData calldata relayData) external;\n\n function executeV3SlowRelayLeaf(\n V3SlowFill calldata slowFillLeaf,\n uint32 rootBundleId,\n bytes32[] calldata proof\n ) external;\n\n /**************************************\n * ERRORS *\n **************************************/\n\n error DisabledRoute();\n error InvalidQuoteTimestamp();\n error InvalidFillDeadline();\n error InvalidExclusiveRelayer();\n error InvalidExclusivityDeadline();\n error MsgValueDoesNotMatchInputAmount();\n error NotExclusiveRelayer();\n error NoSlowFillsInExclusivityWindow();\n error RelayFilled();\n error InvalidSlowFillRequest();\n error ExpiredFillDeadline();\n error InvalidMerkleProof();\n error InvalidChainId();\n error InvalidMerkleLeaf();\n error ClaimedMerkleLeaf();\n error InvalidPayoutAdjustmentPct();\n}\n" + }, + "contracts/SpokePoolVerifier.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/utils/Address.sol\";\nimport \"./interfaces/V3SpokePoolInterface.sol\";\n\n/**\n * @notice SpokePoolVerifier is a contract that verifies that the SpokePool exists on this chain before sending ETH to it.\n * @dev This contract must be deployed via Create2 to the same address on all chains. That way, an errant transaction sent\n * to the wrong chain will be blocked by this contract rather than hitting a dead address. This means that this contract\n * will not work to protect chains, like zkSync, where Create2 address derivations don't match other chains.\n * Source: https://era.zksync.io/docs/reference/architecture/differences-with-ethereum.html#create-create2\n * @custom:security-contact bugs@across.to\n */\ncontract SpokePoolVerifier {\n using Address for address;\n\n /**\n * @notice Passthrough function to `depositV3()` on the SpokePool contract.\n * @dev Protects the caller from losing their ETH (or other native token) by reverting if the SpokePool address\n * they intended to call does not exist on this chain. Because this contract can be deployed at the same address\n * everywhere callers should be protected even if the transaction is submitted to an unintended network.\n * This contract should only be used for native token deposits, as this problem only exists for native tokens.\n * @param spokePool Address of the SpokePool contract that the user is intending to call.\n * @param recipient Address to receive funds at on destination chain.\n * @param inputToken Token to lock into this contract to initiate deposit.\n * @param inputAmount Amount of tokens to deposit.\n * @param outputAmount Amount of tokens to receive on destination chain.\n * @param destinationChainId Denotes network where user will receive funds from SpokePool by a relayer.\n * @param quoteTimestamp Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid\n * to LP pool on HubPool.\n * @param message Arbitrary data that can be used to pass additional information to the recipient along with the tokens.\n * Note: this is intended to be used to pass along instructions for how a contract should use or allocate the tokens.\n * @param exclusiveRelayer Address of the relayer who has exclusive rights to fill this deposit. Can be set to\n * 0x0 if no exclusivity period is desired. If so, then must set exclusivityDeadline to 0.\n * @param exclusivityDeadline Timestamp after which any relayer can fill this deposit. Must set\n * to 0 if exclusiveRelayer is set to 0x0, and vice versa.\n * @param fillDeadline Timestamp after which this deposit can no longer be filled.\n */\n function deposit(\n V3SpokePoolInterface spokePool,\n address recipient,\n address inputToken,\n uint256 inputAmount,\n uint256 outputAmount,\n uint256 destinationChainId,\n uint32 quoteTimestamp,\n bytes memory message,\n address exclusiveRelayer,\n uint32 exclusivityDeadline,\n uint32 fillDeadline\n ) external payable {\n require(msg.value == inputAmount, \"msg.value != amount\");\n require(address(spokePool).isContract(), \"spokePool is not a contract\");\n // Set msg.sender as the depositor so that msg.sender can speed up the deposit.\n spokePool.depositV3{ value: msg.value }(\n msg.sender,\n recipient,\n inputToken,\n // @dev Setting outputToken to 0x0 to instruct fillers to use the equivalent token\n // as the originToken on the destination chain.\n address(0),\n inputAmount,\n outputAmount,\n destinationChainId,\n exclusiveRelayer,\n quoteTimestamp,\n fillDeadline,\n exclusivityDeadline,\n message\n );\n }\n}\n" + } + }, + "settings": { + "optimizer": { + "enabled": true, + "runs": 1000000 + }, + "viaIR": true, + "debug": { + "revertStrings": "strip" + }, + "outputSelection": { + "*": { + "*": [ + "abi", + "evm.bytecode", + "evm.deployedBytecode", + "evm.methodIdentifiers", + "metadata", + "devdoc", + "userdoc", + "storageLayout", + "evm.gasEstimates" + ], + "": ["ast"] + } + }, + "metadata": { + "useLiteralContent": true + } + } +} diff --git a/deployments/polygon/solcInputs/783274f805324492b21545b62eb0dbfe.json b/deployments/polygon/solcInputs/783274f805324492b21545b62eb0dbfe.json new file mode 100644 index 000000000..4bcffc07b --- /dev/null +++ b/deployments/polygon/solcInputs/783274f805324492b21545b62eb0dbfe.json @@ -0,0 +1,43 @@ +{ + "language": "Solidity", + "sources": { + "@openzeppelin/contracts/utils/Address.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (utils/Address.sol)\n\npragma solidity ^0.8.1;\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 * Furthermore, `isContract` will also return true if the target contract within\n * the same transaction is already scheduled for destruction by `SELFDESTRUCT`,\n * which only has an effect at the end of a transaction.\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 > 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://consensys.net/diligence/blog/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.8.0/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n require(address(this).balance >= amount, \"Address: insufficient balance\");\n\n (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 functionCallWithValue(target, data, 0, \"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(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n return functionCallWithValue(target, data, value, \"Address: low-level call with value failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\n * with `errorMessage` as a fallback revert reason when `target` reverts.\n *\n * _Available since v3.1._\n */\n function functionCallWithValue(\n address target,\n bytes memory data,\n uint256 value,\n string memory errorMessage\n ) internal returns (bytes memory) {\n require(address(this).balance >= value, \"Address: insufficient balance for call\");\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, 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 (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, 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 (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata, errorMessage);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling\n * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.\n *\n * _Available since v4.8._\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata,\n string memory errorMessage\n ) internal view returns (bytes memory) {\n if (success) {\n if (returndata.length == 0) {\n // only check isContract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n require(isContract(target), \"Address: call to non-contract\");\n }\n return returndata;\n } else {\n _revert(returndata, errorMessage);\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the\n * revert reason or 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 _revert(returndata, errorMessage);\n }\n }\n\n function _revert(bytes memory returndata, string memory errorMessage) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length > 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert(errorMessage);\n }\n }\n}\n" + }, + "contracts/interfaces/V3SpokePoolInterface.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n// Contains structs and functions used by SpokePool contracts to facilitate universal settlement.\ninterface V3SpokePoolInterface {\n /**************************************\n * ENUMS *\n **************************************/\n\n // Fill status tracks on-chain state of deposit, uniquely identified by relayHash.\n enum FillStatus {\n Unfilled,\n RequestedSlowFill,\n Filled\n }\n // Fill type is emitted in the FilledRelay event to assist Dataworker with determining which types of\n // fills to refund (e.g. only fast fills) and whether a fast fill created a sow fill excess.\n enum FillType {\n FastFill,\n // Fast fills are normal fills that do not replace a slow fill request.\n ReplacedSlowFill,\n // Replaced slow fills are fast fills that replace a slow fill request. This type is used by the Dataworker\n // to know when to send excess funds from the SpokePool to the HubPool because they can no longer be used\n // for a slow fill execution.\n SlowFill\n // Slow fills are requested via requestSlowFill and executed by executeSlowRelayLeaf after a bundle containing\n // the slow fill is validated.\n }\n\n /**************************************\n * STRUCTS *\n **************************************/\n\n // This struct represents the data to fully specify a **unique** relay submitted on this chain.\n // This data is hashed with the chainId() and saved by the SpokePool to prevent collisions and protect against\n // replay attacks on other chains. If any portion of this data differs, the relay is considered to be\n // completely distinct.\n struct V3RelayData {\n // The address that made the deposit on the origin chain.\n address depositor;\n // The recipient address on the destination chain.\n address recipient;\n // This is the exclusive relayer who can fill the deposit before the exclusivity deadline.\n address exclusiveRelayer;\n // Token that is deposited on origin chain by depositor.\n address inputToken;\n // Token that is received on destination chain by recipient.\n address outputToken;\n // The amount of input token deposited by depositor.\n uint256 inputAmount;\n // The amount of output token to be received by recipient.\n uint256 outputAmount;\n // Origin chain id.\n uint256 originChainId;\n // The id uniquely identifying this deposit on the origin chain.\n uint32 depositId;\n // The timestamp on the destination chain after which this deposit can no longer be filled.\n uint32 fillDeadline;\n // The timestamp on the destination chain after which any relayer can fill the deposit.\n uint32 exclusivityDeadline;\n // Data that is forwarded to the recipient.\n bytes message;\n }\n\n // Contains parameters passed in by someone who wants to execute a slow relay leaf.\n struct V3SlowFill {\n V3RelayData relayData;\n uint256 chainId;\n uint256 updatedOutputAmount;\n }\n\n // Contains information about a relay to be sent along with additional information that is not unique to the\n // relay itself but is required to know how to process the relay. For example, \"updatedX\" fields can be used\n // by the relayer to modify fields of the relay with the depositor's permission, and \"repaymentChainId\" is specified\n // by the relayer to determine where to take a relayer refund, but doesn't affect the uniqueness of the relay.\n struct V3RelayExecutionParams {\n V3RelayData relay;\n bytes32 relayHash;\n uint256 updatedOutputAmount;\n address updatedRecipient;\n bytes updatedMessage;\n uint256 repaymentChainId;\n }\n\n // Packs together parameters emitted in FilledV3Relay because there are too many emitted otherwise.\n // Similar to V3RelayExecutionParams, these parameters are not used to uniquely identify the deposit being\n // filled so they don't have to be unpacked by all clients.\n struct V3RelayExecutionEventInfo {\n address updatedRecipient;\n bytes updatedMessage;\n uint256 updatedOutputAmount;\n FillType fillType;\n }\n\n /**************************************\n * EVENTS *\n **************************************/\n\n event V3FundsDeposited(\n address inputToken,\n address outputToken,\n uint256 inputAmount,\n uint256 outputAmount,\n uint256 indexed destinationChainId,\n uint32 indexed depositId,\n uint32 quoteTimestamp,\n uint32 fillDeadline,\n uint32 exclusivityDeadline,\n address indexed depositor,\n address recipient,\n address exclusiveRelayer,\n bytes message\n );\n\n event RequestedSpeedUpV3Deposit(\n uint256 updatedOutputAmount,\n uint32 indexed depositId,\n address indexed depositor,\n address updatedRecipient,\n bytes updatedMessage,\n bytes depositorSignature\n );\n\n event FilledV3Relay(\n address inputToken,\n address outputToken,\n uint256 inputAmount,\n uint256 outputAmount,\n uint256 repaymentChainId,\n uint256 indexed originChainId,\n uint32 indexed depositId,\n uint32 fillDeadline,\n uint32 exclusivityDeadline,\n address exclusiveRelayer,\n address indexed relayer,\n address depositor,\n address recipient,\n bytes message,\n V3RelayExecutionEventInfo relayExecutionInfo\n );\n\n event RequestedV3SlowFill(\n address inputToken,\n address outputToken,\n uint256 inputAmount,\n uint256 outputAmount,\n uint256 indexed originChainId,\n uint32 indexed depositId,\n uint32 fillDeadline,\n uint32 exclusivityDeadline,\n address exclusiveRelayer,\n address depositor,\n address recipient,\n bytes message\n );\n\n /**************************************\n * FUNCTIONS *\n **************************************/\n\n function depositV3(\n address depositor,\n address recipient,\n address inputToken,\n address outputToken,\n uint256 inputAmount,\n uint256 outputAmount,\n uint256 destinationChainId,\n address exclusiveRelayer,\n uint32 quoteTimestamp,\n uint32 fillDeadline,\n uint32 exclusivityDeadline,\n bytes calldata message\n ) external payable;\n\n function depositV3Now(\n address depositor,\n address recipient,\n address inputToken,\n address outputToken,\n uint256 inputAmount,\n uint256 outputAmount,\n uint256 destinationChainId,\n address exclusiveRelayer,\n uint32 fillDeadlineOffset,\n uint32 exclusivityDeadline,\n bytes calldata message\n ) external payable;\n\n function speedUpV3Deposit(\n address depositor,\n uint32 depositId,\n uint256 updatedOutputAmount,\n address updatedRecipient,\n bytes calldata updatedMessage,\n bytes calldata depositorSignature\n ) external;\n\n function fillV3Relay(V3RelayData calldata relayData, uint256 repaymentChainId) external;\n\n function fillV3RelayWithUpdatedDeposit(\n V3RelayData calldata relayData,\n uint256 repaymentChainId,\n uint256 updatedOutputAmount,\n address updatedRecipient,\n bytes calldata updatedMessage,\n bytes calldata depositorSignature\n ) external;\n\n function requestV3SlowFill(V3RelayData calldata relayData) external;\n\n function executeV3SlowRelayLeaf(\n V3SlowFill calldata slowFillLeaf,\n uint32 rootBundleId,\n bytes32[] calldata proof\n ) external;\n\n /**************************************\n * ERRORS *\n **************************************/\n\n error DisabledRoute();\n error InvalidQuoteTimestamp();\n error InvalidFillDeadline();\n error InvalidExclusiveRelayer();\n error InvalidExclusivityDeadline();\n error MsgValueDoesNotMatchInputAmount();\n error NotExclusiveRelayer();\n error NoSlowFillsInExclusivityWindow();\n error RelayFilled();\n error InvalidSlowFillRequest();\n error ExpiredFillDeadline();\n error InvalidMerkleProof();\n error InvalidChainId();\n error InvalidMerkleLeaf();\n error ClaimedMerkleLeaf();\n error InvalidPayoutAdjustmentPct();\n}\n" + }, + "contracts/SpokePoolVerifier.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/utils/Address.sol\";\nimport \"./interfaces/V3SpokePoolInterface.sol\";\n\n/**\n * @notice SpokePoolVerifier is a contract that verifies that the SpokePool exists on this chain before sending ETH to it.\n * @dev This contract must be deployed via Create2 to the same address on all chains. That way, an errant transaction sent\n * to the wrong chain will be blocked by this contract rather than hitting a dead address. This means that this contract\n * will not work to protect chains, like zkSync, where Create2 address derivations don't match other chains.\n * Source: https://era.zksync.io/docs/reference/architecture/differences-with-ethereum.html#create-create2\n * @custom:security-contact bugs@across.to\n */\ncontract SpokePoolVerifier {\n using Address for address;\n\n /**\n * @notice Passthrough function to `depositV3()` on the SpokePool contract.\n * @dev Protects the caller from losing their ETH (or other native token) by reverting if the SpokePool address\n * they intended to call does not exist on this chain. Because this contract can be deployed at the same address\n * everywhere callers should be protected even if the transaction is submitted to an unintended network.\n * This contract should only be used for native token deposits, as this problem only exists for native tokens.\n * @param spokePool Address of the SpokePool contract that the user is intending to call.\n * @param recipient Address to receive funds at on destination chain.\n * @param inputToken Token to lock into this contract to initiate deposit.\n * @param inputAmount Amount of tokens to deposit.\n * @param outputAmount Amount of tokens to receive on destination chain.\n * @param destinationChainId Denotes network where user will receive funds from SpokePool by a relayer.\n * @param quoteTimestamp Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid\n * to LP pool on HubPool.\n * @param message Arbitrary data that can be used to pass additional information to the recipient along with the tokens.\n * Note: this is intended to be used to pass along instructions for how a contract should use or allocate the tokens.\n * @param exclusiveRelayer Address of the relayer who has exclusive rights to fill this deposit. Can be set to\n * 0x0 if no exclusivity period is desired. If so, then must set exclusivityDeadline to 0.\n * @param exclusivityDeadline Timestamp after which any relayer can fill this deposit. Must set\n * to 0 if exclusiveRelayer is set to 0x0, and vice versa.\n * @param fillDeadline Timestamp after which this deposit can no longer be filled.\n */\n function deposit(\n V3SpokePoolInterface spokePool,\n address recipient,\n address inputToken,\n uint256 inputAmount,\n uint256 outputAmount,\n uint256 destinationChainId,\n address exclusiveRelayer,\n uint32 quoteTimestamp,\n uint32 fillDeadline,\n uint32 exclusivityDeadline,\n bytes memory message\n ) external payable {\n require(msg.value == inputAmount, \"msg.value != amount\");\n require(address(spokePool).isContract(), \"spokePool is not a contract\");\n // Set msg.sender as the depositor so that msg.sender can speed up the deposit.\n spokePool.depositV3{ value: msg.value }(\n msg.sender,\n recipient,\n inputToken,\n // @dev Setting outputToken to 0x0 to instruct fillers to use the equivalent token\n // as the originToken on the destination chain.\n address(0),\n inputAmount,\n outputAmount,\n destinationChainId,\n exclusiveRelayer,\n quoteTimestamp,\n fillDeadline,\n exclusivityDeadline,\n message\n );\n }\n}\n" + } + }, + "settings": { + "optimizer": { + "enabled": true, + "runs": 1000000 + }, + "viaIR": true, + "debug": { + "revertStrings": "strip" + }, + "outputSelection": { + "*": { + "*": [ + "abi", + "evm.bytecode", + "evm.deployedBytecode", + "evm.methodIdentifiers", + "metadata", + "devdoc", + "userdoc", + "storageLayout", + "evm.gasEstimates" + ], + "": ["ast"] + } + }, + "metadata": { + "useLiteralContent": true + } + } +} diff --git a/deployments/scroll/SpokePoolVerifier.json b/deployments/scroll/SpokePoolVerifier.json index 650d9e4b6..88ae618f1 100644 --- a/deployments/scroll/SpokePoolVerifier.json +++ b/deployments/scroll/SpokePoolVerifier.json @@ -1,10 +1,10 @@ { - "address": "0xB4A8d45647445EA9FC3E1058096142390683dBC2", + "address": "0x4437A1Ee2dFb72954F21A44C3F0F0E2CBA5A5C27", "abi": [ { "inputs": [ { - "internalType": "contract SpokePoolInterface", + "internalType": "contract V3SpokePoolInterface", "name": "spokePool", "type": "address" }, @@ -15,12 +15,17 @@ }, { "internalType": "address", - "name": "originToken", + "name": "inputToken", "type": "address" }, { "internalType": "uint256", - "name": "amount", + "name": "inputAmount", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "outputAmount", "type": "uint256" }, { @@ -29,24 +34,29 @@ "type": "uint256" }, { - "internalType": "int64", - "name": "relayerFeePct", - "type": "int64" + "internalType": "address", + "name": "exclusiveRelayer", + "type": "address" }, { "internalType": "uint32", "name": "quoteTimestamp", "type": "uint32" }, + { + "internalType": "uint32", + "name": "fillDeadline", + "type": "uint32" + }, + { + "internalType": "uint32", + "name": "exclusivityDeadline", + "type": "uint32" + }, { "internalType": "bytes", "name": "message", "type": "bytes" - }, - { - "internalType": "uint256", - "name": "maxCount", - "type": "uint256" } ], "name": "deposit", @@ -55,43 +65,46 @@ "type": "function" } ], - "transactionHash": "0xedcb6fa28214738892dfb98b1dd13d77b973971cc70fdf0d101a9a723a5c3f12", + "transactionHash": "0x0568b7bf86f5dd901314e9abb6493b44e0f707c403d8dad9b9b6f556fef9d332", "receipt": { "to": "0x4e59b44847b379578588920cA78FbF26c0B4956C", "from": "0x9A8f92a830A5cB89a3816e3D267CB7791c16b04D", "contractAddress": null, - "transactionIndex": 5, - "gasUsed": "234906", + "transactionIndex": 6, + "gasUsed": "254525", "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - "blockHash": "0xfc20795002526a1982f2d5ffb8311e78ab0146be91418c14fe06d0ac6840b1da", - "transactionHash": "0xedcb6fa28214738892dfb98b1dd13d77b973971cc70fdf0d101a9a723a5c3f12", + "blockHash": "0x38caa664040045d5c18b9c319d3b8a69000ee6318edb22e8ca40fbaafec06209", + "transactionHash": "0x0568b7bf86f5dd901314e9abb6493b44e0f707c403d8dad9b9b6f556fef9d332", "logs": [], - "blockNumber": 7490003, - "cumulativeGasUsed": "771948", + "blockNumber": 7800129, + "cumulativeGasUsed": "1271203", "status": 1, "byzantium": true }, "args": [], - "numDeployments": 1, - "solcInputHash": "53ab13385da43753d9a657e7780a0560", - "metadata": "{\"compiler\":{\"version\":\"0.8.19+commit.7dd6d404\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"contract SpokePoolInterface\",\"name\":\"spokePool\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"internalType\":\"int64\",\"name\":\"relayerFeePct\",\"type\":\"int64\"},{\"internalType\":\"uint32\",\"name\":\"quoteTimestamp\",\"type\":\"uint32\"},{\"internalType\":\"bytes\",\"name\":\"message\",\"type\":\"bytes\"},{\"internalType\":\"uint256\",\"name\":\"maxCount\",\"type\":\"uint256\"}],\"name\":\"deposit\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"This contract must be deployed via Create2 to the same address on all chains. That way, an errant transaction sent to the wrong chain will be blocked by this contract rather than hitting a dead address. This means that this contract will not work to protect chains, like zkSync, where Create2 address derivations don't match other chains. Source: https://era.zksync.io/docs/reference/architecture/differences-with-ethereum.html#create-create2\",\"kind\":\"dev\",\"methods\":{\"deposit(address,address,address,uint256,uint256,int64,uint32,bytes,uint256)\":{\"details\":\"Protects the caller from losing their ETH (or other native token) by reverting if the SpokePool address they intended to call does not exist on this chain. Because this contract can be deployed at the same address everywhere callers should be protected even if the transaction is submitted to an unintended network. This contract should only be used for native token deposits, as this problem only exists for native tokens.\",\"params\":{\"amount\":\"Amount of tokens to deposit. Will be amount of tokens to receive less fees.\",\"destinationChainId\":\"Denotes network where user will receive funds from SpokePool by a relayer.\",\"maxCount\":\"used to protect the depositor from frontrunning to guarantee their quote remains valid. Note: this is intended to be used to pass along instructions for how a contract should use or allocate the tokens.\",\"message\":\"Arbitrary data that can be used to pass additional information to the recipient along with the tokens. Note: this is intended to be used to pass along instructions for how a contract should use or allocate the tokens.\",\"originToken\":\"Token to lock into this contract to initiate deposit.\",\"quoteTimestamp\":\"Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid to LP pool on HubPool.\",\"recipient\":\"Address to receive funds at on destination chain.\",\"relayerFeePct\":\"% of deposit amount taken out to incentivize a fast relayer.\",\"spokePool\":\"Address of the SpokePool contract that the user is intending to call.\"}}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"deposit(address,address,address,uint256,uint256,int64,uint32,bytes,uint256)\":{\"notice\":\"Passthrough function to `depositV3()` on the SpokePool contract.\"}},\"notice\":\"SpokePoolVerifier is a contract that verifies that the SpokePool exists on this chain before sending ETH to it.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/SpokePoolVerifier.sol\":\"SpokePoolVerifier\"},\"debug\":{\"revertStrings\":\"strip\"},\"evmVersion\":\"paris\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":1000000},\"remappings\":[],\"viaIR\":true},\"sources\":{\"@openzeppelin/contracts/utils/Address.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.9.0) (utils/Address.sol)\\n\\npragma solidity ^0.8.1;\\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 * Furthermore, `isContract` will also return true if the target contract within\\n * the same transaction is already scheduled for destruction by `SELFDESTRUCT`,\\n * which only has an effect at the end of a transaction.\\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 > 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://consensys.net/diligence/blog/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.8.0/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\\n */\\n function sendValue(address payable recipient, uint256 amount) internal {\\n require(address(this).balance >= amount, \\\"Address: insufficient balance\\\");\\n\\n (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 functionCallWithValue(target, data, 0, \\\"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(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, value, \\\"Address: low-level call with value failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\\n * with `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(address(this).balance >= value, \\\"Address: insufficient balance for call\\\");\\n (bool success, bytes memory returndata) = target.call{value: value}(data);\\n return verifyCallResultFromTarget(target, 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 (bool success, bytes memory returndata) = target.staticcall(data);\\n return verifyCallResultFromTarget(target, 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 (bool success, bytes memory returndata) = target.delegatecall(data);\\n return verifyCallResultFromTarget(target, success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling\\n * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.\\n *\\n * _Available since v4.8._\\n */\\n function verifyCallResultFromTarget(\\n address target,\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n if (success) {\\n if (returndata.length == 0) {\\n // only check isContract if the call was successful and the return data is empty\\n // otherwise we already know that it was a contract\\n require(isContract(target), \\\"Address: call to non-contract\\\");\\n }\\n return returndata;\\n } else {\\n _revert(returndata, errorMessage);\\n }\\n }\\n\\n /**\\n * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the\\n * revert reason or 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 _revert(returndata, errorMessage);\\n }\\n }\\n\\n function _revert(bytes memory returndata, string memory errorMessage) private pure {\\n // Look for revert reason and bubble it up if present\\n if (returndata.length > 0) {\\n // The easiest way to bubble the revert reason is using memory via assembly\\n /// @solidity memory-safe-assembly\\n assembly {\\n let returndata_size := mload(returndata)\\n revert(add(32, returndata), returndata_size)\\n }\\n } else {\\n revert(errorMessage);\\n }\\n }\\n}\\n\",\"keccak256\":\"0x006dd67219697fe68d7fbfdea512e7c4cb64a43565ed86171d67e844982da6fa\",\"license\":\"MIT\"},\"contracts/SpokePoolVerifier.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\nimport \\\"@openzeppelin/contracts/utils/Address.sol\\\";\\nimport \\\"./interfaces/SpokePoolInterface.sol\\\";\\n\\n/**\\n * @notice SpokePoolVerifier is a contract that verifies that the SpokePool exists on this chain before sending ETH to it.\\n * @dev This contract must be deployed via Create2 to the same address on all chains. That way, an errant transaction sent\\n * to the wrong chain will be blocked by this contract rather than hitting a dead address. This means that this contract\\n * will not work to protect chains, like zkSync, where Create2 address derivations don't match other chains.\\n * Source: https://era.zksync.io/docs/reference/architecture/differences-with-ethereum.html#create-create2\\n */\\ncontract SpokePoolVerifier {\\n using Address for address;\\n\\n /**\\n * @notice Passthrough function to `depositV3()` on the SpokePool contract.\\n * @dev Protects the caller from losing their ETH (or other native token) by reverting if the SpokePool address\\n * they intended to call does not exist on this chain. Because this contract can be deployed at the same address\\n * everywhere callers should be protected even if the transaction is submitted to an unintended network.\\n * This contract should only be used for native token deposits, as this problem only exists for native tokens.\\n * @param spokePool Address of the SpokePool contract that the user is intending to call.\\n * @param recipient Address to receive funds at on destination chain.\\n * @param originToken Token to lock into this contract to initiate deposit.\\n * @param amount Amount of tokens to deposit. Will be amount of tokens to receive less fees.\\n * @param destinationChainId Denotes network where user will receive funds from SpokePool by a relayer.\\n * @param relayerFeePct % of deposit amount taken out to incentivize a fast relayer.\\n * @param quoteTimestamp Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid\\n * to LP pool on HubPool.\\n * @param message Arbitrary data that can be used to pass additional information to the recipient along with the tokens.\\n * Note: this is intended to be used to pass along instructions for how a contract should use or allocate the tokens.\\n * @param maxCount used to protect the depositor from frontrunning to guarantee their quote remains valid.\\n * Note: this is intended to be used to pass along instructions for how a contract should use or allocate the tokens.\\n */\\n function deposit(\\n SpokePoolInterface spokePool,\\n address recipient,\\n address originToken,\\n uint256 amount,\\n uint256 destinationChainId,\\n int64 relayerFeePct,\\n uint32 quoteTimestamp,\\n bytes memory message,\\n uint256 maxCount\\n ) external payable {\\n require(msg.value == amount, \\\"msg.value != amount\\\");\\n require(address(spokePool).isContract(), \\\"spokePool is not a contract\\\");\\n // Set msg.sender as the depositor so that msg.sender can speed up the deposit.\\n spokePool.depositFor{ value: msg.value }(\\n msg.sender,\\n recipient,\\n originToken,\\n amount,\\n destinationChainId,\\n relayerFeePct,\\n quoteTimestamp,\\n message,\\n maxCount\\n );\\n }\\n}\\n\",\"keccak256\":\"0xfc008c31a2fde7eb0daedaa823b76931225f41ac882b6d1c515d8a38ccda60ec\",\"license\":\"BUSL-1.1\"},\"contracts/interfaces/SpokePoolInterface.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\n/**\\n * @notice Contains common data structures and functions used by all SpokePool implementations.\\n */\\ninterface SpokePoolInterface {\\n // This leaf is meant to be decoded in the SpokePool to pay out successful relayers.\\n struct RelayerRefundLeaf {\\n // This is the amount to return to the HubPool. This occurs when there is a PoolRebalanceLeaf netSendAmount that\\n // is negative. This is just the negative of this value.\\n uint256 amountToReturn;\\n // Used to verify that this is being executed on the correct destination chainId.\\n uint256 chainId;\\n // This array designates how much each of those addresses should be refunded.\\n uint256[] refundAmounts;\\n // Used as the index in the bitmap to track whether this leaf has been executed or not.\\n uint32 leafId;\\n // The associated L2TokenAddress that these claims apply to.\\n address l2TokenAddress;\\n // Must be same length as refundAmounts and designates each address that must be refunded.\\n address[] refundAddresses;\\n }\\n\\n // Stores collection of merkle roots that can be published to this contract from the HubPool, which are referenced\\n // by \\\"data workers\\\" via inclusion proofs to execute leaves in the roots.\\n struct RootBundle {\\n // Merkle root of slow relays that were not fully filled and whose recipient is still owed funds from the LP pool.\\n bytes32 slowRelayRoot;\\n // Merkle root of relayer refunds for successful relays.\\n bytes32 relayerRefundRoot;\\n // This is a 2D bitmap tracking which leaves in the relayer refund root have been claimed, with max size of\\n // 256x(2^248) leaves per root.\\n mapping(uint256 => uint256) claimedBitmap;\\n }\\n\\n function setCrossDomainAdmin(address newCrossDomainAdmin) external;\\n\\n function setHubPool(address newHubPool) external;\\n\\n function setEnableRoute(\\n address originToken,\\n uint256 destinationChainId,\\n bool enable\\n ) external;\\n\\n function pauseDeposits(bool pause) external;\\n\\n function pauseFills(bool pause) external;\\n\\n function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) external;\\n\\n function emergencyDeleteRootBundle(uint256 rootBundleId) external;\\n\\n function deposit(\\n address recipient,\\n address originToken,\\n uint256 amount,\\n uint256 destinationChainId,\\n int64 relayerFeePct,\\n uint32 quoteTimestamp,\\n bytes memory message,\\n uint256 maxCount\\n ) external payable;\\n\\n function depositFor(\\n address depositor,\\n address recipient,\\n address originToken,\\n uint256 amount,\\n uint256 destinationChainId,\\n int64 relayerFeePct,\\n uint32 quoteTimestamp,\\n bytes memory message,\\n uint256 maxCount\\n ) external payable;\\n\\n function executeRelayerRefundLeaf(\\n uint32 rootBundleId,\\n SpokePoolInterface.RelayerRefundLeaf memory relayerRefundLeaf,\\n bytes32[] memory proof\\n ) external payable;\\n\\n function chainId() external view returns (uint256);\\n\\n error NotEOA();\\n error InvalidDepositorSignature();\\n error InvalidRelayerFeePct();\\n error MaxTransferSizeExceeded();\\n error InvalidCrossDomainAdmin();\\n error InvalidHubPool();\\n error DepositsArePaused();\\n error FillsArePaused();\\n}\\n\",\"keccak256\":\"0xc90fbd7e66e2e87e9aacbe93c20cc020cd1fc582c4fd4879807e7dc026943ea0\",\"license\":\"BUSL-1.1\"}},\"version\":1}", - "bytecode": "0x608080604052346100165761034b908161001c8239f35b600080fdfe600436101561000d57600080fd5b6000803560e01c63e0db3fcf1461002357600080fd5b610120807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103115773ffffffffffffffffffffffffffffffffffffffff600435818116810361030d576024359282841684036103095760443583811681036103055760a4358060070b81036103015760c4359063ffffffff8216820361029b5760e43567ffffffffffffffff81116102fd57366023820112156102fd57806004013567ffffffffffffffff81116102d0577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0603f81601f84011601166080016080811067ffffffffffffffff8211176102a357908a929160405280608052366024828401011161029f57602091819060240160a0376080010152606435340361029b578585163b1561029b578585163b1561029b57859694929163ffffffff91878a9896946040519a8b997f541f4f14000000000000000000000000000000000000000000000000000000008b523360048c01521660248a01521660448801526064356064880152608435608488015260070b60a48701521660c485015260e484015260805180610124850152845b8181106102805750908391827fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f6101449389858286010152610104803590850152011681010301923491165af1801561027557610233575080f35b67ffffffffffffffff81116102485760405280f35b6024827f4e487b710000000000000000000000000000000000000000000000000000000081526041600452fd5b6040513d84823e3d90fd5b60a081015187820161014401528795508694506020016101d6565b8780fd5b8280fd5b60248b7f4e487b710000000000000000000000000000000000000000000000000000000081526041600452fd5b60248a7f4e487b710000000000000000000000000000000000000000000000000000000081526041600452fd5b8880fd5b8680fd5b8580fd5b8480fd5b8380fd5b5080fdfea26469706673582212204f81f550f00970671d0755020f959a6599fd76306000e67b424172e1089b949a64736f6c63430008130033", - "deployedBytecode": "0x600436101561000d57600080fd5b6000803560e01c63e0db3fcf1461002357600080fd5b610120807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103115773ffffffffffffffffffffffffffffffffffffffff600435818116810361030d576024359282841684036103095760443583811681036103055760a4358060070b81036103015760c4359063ffffffff8216820361029b5760e43567ffffffffffffffff81116102fd57366023820112156102fd57806004013567ffffffffffffffff81116102d0577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0603f81601f84011601166080016080811067ffffffffffffffff8211176102a357908a929160405280608052366024828401011161029f57602091819060240160a0376080010152606435340361029b578585163b1561029b578585163b1561029b57859694929163ffffffff91878a9896946040519a8b997f541f4f14000000000000000000000000000000000000000000000000000000008b523360048c01521660248a01521660448801526064356064880152608435608488015260070b60a48701521660c485015260e484015260805180610124850152845b8181106102805750908391827fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f6101449389858286010152610104803590850152011681010301923491165af1801561027557610233575080f35b67ffffffffffffffff81116102485760405280f35b6024827f4e487b710000000000000000000000000000000000000000000000000000000081526041600452fd5b6040513d84823e3d90fd5b60a081015187820161014401528795508694506020016101d6565b8780fd5b8280fd5b60248b7f4e487b710000000000000000000000000000000000000000000000000000000081526041600452fd5b60248a7f4e487b710000000000000000000000000000000000000000000000000000000081526041600452fd5b8880fd5b8680fd5b8580fd5b8480fd5b8380fd5b5080fdfea26469706673582212204f81f550f00970671d0755020f959a6599fd76306000e67b424172e1089b949a64736f6c63430008130033", + "numDeployments": 3, + "solcInputHash": "783274f805324492b21545b62eb0dbfe", + "metadata": "{\"compiler\":{\"version\":\"0.8.19+commit.7dd6d404\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"contract V3SpokePoolInterface\",\"name\":\"spokePool\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"inputToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"inputAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"outputAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destinationChainId\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"exclusiveRelayer\",\"type\":\"address\"},{\"internalType\":\"uint32\",\"name\":\"quoteTimestamp\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"fillDeadline\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"exclusivityDeadline\",\"type\":\"uint32\"},{\"internalType\":\"bytes\",\"name\":\"message\",\"type\":\"bytes\"}],\"name\":\"deposit\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"}],\"devdoc\":{\"custom:security-contact\":\"bugs@across.to\",\"details\":\"This contract must be deployed via Create2 to the same address on all chains. That way, an errant transaction sent to the wrong chain will be blocked by this contract rather than hitting a dead address. This means that this contract will not work to protect chains, like zkSync, where Create2 address derivations don't match other chains. Source: https://era.zksync.io/docs/reference/architecture/differences-with-ethereum.html#create-create2\",\"kind\":\"dev\",\"methods\":{\"deposit(address,address,address,uint256,uint256,uint256,address,uint32,uint32,uint32,bytes)\":{\"details\":\"Protects the caller from losing their ETH (or other native token) by reverting if the SpokePool address they intended to call does not exist on this chain. Because this contract can be deployed at the same address everywhere callers should be protected even if the transaction is submitted to an unintended network. This contract should only be used for native token deposits, as this problem only exists for native tokens.\",\"params\":{\"destinationChainId\":\"Denotes network where user will receive funds from SpokePool by a relayer.\",\"exclusiveRelayer\":\"Address of the relayer who has exclusive rights to fill this deposit. Can be set to 0x0 if no exclusivity period is desired. If so, then must set exclusivityDeadline to 0.\",\"exclusivityDeadline\":\"Timestamp after which any relayer can fill this deposit. Must set to 0 if exclusiveRelayer is set to 0x0, and vice versa.\",\"fillDeadline\":\"Timestamp after which this deposit can no longer be filled.\",\"inputAmount\":\"Amount of tokens to deposit.\",\"inputToken\":\"Token to lock into this contract to initiate deposit.\",\"message\":\"Arbitrary data that can be used to pass additional information to the recipient along with the tokens. Note: this is intended to be used to pass along instructions for how a contract should use or allocate the tokens.\",\"outputAmount\":\"Amount of tokens to receive on destination chain.\",\"quoteTimestamp\":\"Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid to LP pool on HubPool.\",\"recipient\":\"Address to receive funds at on destination chain.\",\"spokePool\":\"Address of the SpokePool contract that the user is intending to call.\"}}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"deposit(address,address,address,uint256,uint256,uint256,address,uint32,uint32,uint32,bytes)\":{\"notice\":\"Passthrough function to `depositV3()` on the SpokePool contract.\"}},\"notice\":\"SpokePoolVerifier is a contract that verifies that the SpokePool exists on this chain before sending ETH to it.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/SpokePoolVerifier.sol\":\"SpokePoolVerifier\"},\"debug\":{\"revertStrings\":\"strip\"},\"evmVersion\":\"paris\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":1000000},\"remappings\":[],\"viaIR\":true},\"sources\":{\"@openzeppelin/contracts/utils/Address.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.9.0) (utils/Address.sol)\\n\\npragma solidity ^0.8.1;\\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 * Furthermore, `isContract` will also return true if the target contract within\\n * the same transaction is already scheduled for destruction by `SELFDESTRUCT`,\\n * which only has an effect at the end of a transaction.\\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 > 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://consensys.net/diligence/blog/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.8.0/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\\n */\\n function sendValue(address payable recipient, uint256 amount) internal {\\n require(address(this).balance >= amount, \\\"Address: insufficient balance\\\");\\n\\n (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 functionCallWithValue(target, data, 0, \\\"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(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, value, \\\"Address: low-level call with value failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\\n * with `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(address(this).balance >= value, \\\"Address: insufficient balance for call\\\");\\n (bool success, bytes memory returndata) = target.call{value: value}(data);\\n return verifyCallResultFromTarget(target, 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 (bool success, bytes memory returndata) = target.staticcall(data);\\n return verifyCallResultFromTarget(target, 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 (bool success, bytes memory returndata) = target.delegatecall(data);\\n return verifyCallResultFromTarget(target, success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling\\n * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.\\n *\\n * _Available since v4.8._\\n */\\n function verifyCallResultFromTarget(\\n address target,\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n if (success) {\\n if (returndata.length == 0) {\\n // only check isContract if the call was successful and the return data is empty\\n // otherwise we already know that it was a contract\\n require(isContract(target), \\\"Address: call to non-contract\\\");\\n }\\n return returndata;\\n } else {\\n _revert(returndata, errorMessage);\\n }\\n }\\n\\n /**\\n * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the\\n * revert reason or 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 _revert(returndata, errorMessage);\\n }\\n }\\n\\n function _revert(bytes memory returndata, string memory errorMessage) private pure {\\n // Look for revert reason and bubble it up if present\\n if (returndata.length > 0) {\\n // The easiest way to bubble the revert reason is using memory via assembly\\n /// @solidity memory-safe-assembly\\n assembly {\\n let returndata_size := mload(returndata)\\n revert(add(32, returndata), returndata_size)\\n }\\n } else {\\n revert(errorMessage);\\n }\\n }\\n}\\n\",\"keccak256\":\"0x006dd67219697fe68d7fbfdea512e7c4cb64a43565ed86171d67e844982da6fa\",\"license\":\"MIT\"},\"contracts/SpokePoolVerifier.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\nimport \\\"@openzeppelin/contracts/utils/Address.sol\\\";\\nimport \\\"./interfaces/V3SpokePoolInterface.sol\\\";\\n\\n/**\\n * @notice SpokePoolVerifier is a contract that verifies that the SpokePool exists on this chain before sending ETH to it.\\n * @dev This contract must be deployed via Create2 to the same address on all chains. That way, an errant transaction sent\\n * to the wrong chain will be blocked by this contract rather than hitting a dead address. This means that this contract\\n * will not work to protect chains, like zkSync, where Create2 address derivations don't match other chains.\\n * Source: https://era.zksync.io/docs/reference/architecture/differences-with-ethereum.html#create-create2\\n * @custom:security-contact bugs@across.to\\n */\\ncontract SpokePoolVerifier {\\n using Address for address;\\n\\n /**\\n * @notice Passthrough function to `depositV3()` on the SpokePool contract.\\n * @dev Protects the caller from losing their ETH (or other native token) by reverting if the SpokePool address\\n * they intended to call does not exist on this chain. Because this contract can be deployed at the same address\\n * everywhere callers should be protected even if the transaction is submitted to an unintended network.\\n * This contract should only be used for native token deposits, as this problem only exists for native tokens.\\n * @param spokePool Address of the SpokePool contract that the user is intending to call.\\n * @param recipient Address to receive funds at on destination chain.\\n * @param inputToken Token to lock into this contract to initiate deposit.\\n * @param inputAmount Amount of tokens to deposit.\\n * @param outputAmount Amount of tokens to receive on destination chain.\\n * @param destinationChainId Denotes network where user will receive funds from SpokePool by a relayer.\\n * @param quoteTimestamp Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid\\n * to LP pool on HubPool.\\n * @param message Arbitrary data that can be used to pass additional information to the recipient along with the tokens.\\n * Note: this is intended to be used to pass along instructions for how a contract should use or allocate the tokens.\\n * @param exclusiveRelayer Address of the relayer who has exclusive rights to fill this deposit. Can be set to\\n * 0x0 if no exclusivity period is desired. If so, then must set exclusivityDeadline to 0.\\n * @param exclusivityDeadline Timestamp after which any relayer can fill this deposit. Must set\\n * to 0 if exclusiveRelayer is set to 0x0, and vice versa.\\n * @param fillDeadline Timestamp after which this deposit can no longer be filled.\\n */\\n function deposit(\\n V3SpokePoolInterface spokePool,\\n address recipient,\\n address inputToken,\\n uint256 inputAmount,\\n uint256 outputAmount,\\n uint256 destinationChainId,\\n address exclusiveRelayer,\\n uint32 quoteTimestamp,\\n uint32 fillDeadline,\\n uint32 exclusivityDeadline,\\n bytes memory message\\n ) external payable {\\n require(msg.value == inputAmount, \\\"msg.value != amount\\\");\\n require(address(spokePool).isContract(), \\\"spokePool is not a contract\\\");\\n // Set msg.sender as the depositor so that msg.sender can speed up the deposit.\\n spokePool.depositV3{ value: msg.value }(\\n msg.sender,\\n recipient,\\n inputToken,\\n // @dev Setting outputToken to 0x0 to instruct fillers to use the equivalent token\\n // as the originToken on the destination chain.\\n address(0),\\n inputAmount,\\n outputAmount,\\n destinationChainId,\\n exclusiveRelayer,\\n quoteTimestamp,\\n fillDeadline,\\n exclusivityDeadline,\\n message\\n );\\n }\\n}\\n\",\"keccak256\":\"0xd5b1ec1b7048634a8b0a7e1e2c68ce51e410157b14778a207b64aff49bc5c6f0\",\"license\":\"BUSL-1.1\"},\"contracts/interfaces/V3SpokePoolInterface.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity ^0.8.0;\\n\\n// Contains structs and functions used by SpokePool contracts to facilitate universal settlement.\\ninterface V3SpokePoolInterface {\\n /**************************************\\n * ENUMS *\\n **************************************/\\n\\n // Fill status tracks on-chain state of deposit, uniquely identified by relayHash.\\n enum FillStatus {\\n Unfilled,\\n RequestedSlowFill,\\n Filled\\n }\\n // Fill type is emitted in the FilledRelay event to assist Dataworker with determining which types of\\n // fills to refund (e.g. only fast fills) and whether a fast fill created a sow fill excess.\\n enum FillType {\\n FastFill,\\n // Fast fills are normal fills that do not replace a slow fill request.\\n ReplacedSlowFill,\\n // Replaced slow fills are fast fills that replace a slow fill request. This type is used by the Dataworker\\n // to know when to send excess funds from the SpokePool to the HubPool because they can no longer be used\\n // for a slow fill execution.\\n SlowFill\\n // Slow fills are requested via requestSlowFill and executed by executeSlowRelayLeaf after a bundle containing\\n // the slow fill is validated.\\n }\\n\\n /**************************************\\n * STRUCTS *\\n **************************************/\\n\\n // This struct represents the data to fully specify a **unique** relay submitted on this chain.\\n // This data is hashed with the chainId() and saved by the SpokePool to prevent collisions and protect against\\n // replay attacks on other chains. If any portion of this data differs, the relay is considered to be\\n // completely distinct.\\n struct V3RelayData {\\n // The address that made the deposit on the origin chain.\\n address depositor;\\n // The recipient address on the destination chain.\\n address recipient;\\n // This is the exclusive relayer who can fill the deposit before the exclusivity deadline.\\n address exclusiveRelayer;\\n // Token that is deposited on origin chain by depositor.\\n address inputToken;\\n // Token that is received on destination chain by recipient.\\n address outputToken;\\n // The amount of input token deposited by depositor.\\n uint256 inputAmount;\\n // The amount of output token to be received by recipient.\\n uint256 outputAmount;\\n // Origin chain id.\\n uint256 originChainId;\\n // The id uniquely identifying this deposit on the origin chain.\\n uint32 depositId;\\n // The timestamp on the destination chain after which this deposit can no longer be filled.\\n uint32 fillDeadline;\\n // The timestamp on the destination chain after which any relayer can fill the deposit.\\n uint32 exclusivityDeadline;\\n // Data that is forwarded to the recipient.\\n bytes message;\\n }\\n\\n // Contains parameters passed in by someone who wants to execute a slow relay leaf.\\n struct V3SlowFill {\\n V3RelayData relayData;\\n uint256 chainId;\\n uint256 updatedOutputAmount;\\n }\\n\\n // Contains information about a relay to be sent along with additional information that is not unique to the\\n // relay itself but is required to know how to process the relay. For example, \\\"updatedX\\\" fields can be used\\n // by the relayer to modify fields of the relay with the depositor's permission, and \\\"repaymentChainId\\\" is specified\\n // by the relayer to determine where to take a relayer refund, but doesn't affect the uniqueness of the relay.\\n struct V3RelayExecutionParams {\\n V3RelayData relay;\\n bytes32 relayHash;\\n uint256 updatedOutputAmount;\\n address updatedRecipient;\\n bytes updatedMessage;\\n uint256 repaymentChainId;\\n }\\n\\n // Packs together parameters emitted in FilledV3Relay because there are too many emitted otherwise.\\n // Similar to V3RelayExecutionParams, these parameters are not used to uniquely identify the deposit being\\n // filled so they don't have to be unpacked by all clients.\\n struct V3RelayExecutionEventInfo {\\n address updatedRecipient;\\n bytes updatedMessage;\\n uint256 updatedOutputAmount;\\n FillType fillType;\\n }\\n\\n /**************************************\\n * EVENTS *\\n **************************************/\\n\\n event V3FundsDeposited(\\n address inputToken,\\n address outputToken,\\n uint256 inputAmount,\\n uint256 outputAmount,\\n uint256 indexed destinationChainId,\\n uint32 indexed depositId,\\n uint32 quoteTimestamp,\\n uint32 fillDeadline,\\n uint32 exclusivityDeadline,\\n address indexed depositor,\\n address recipient,\\n address exclusiveRelayer,\\n bytes message\\n );\\n\\n event RequestedSpeedUpV3Deposit(\\n uint256 updatedOutputAmount,\\n uint32 indexed depositId,\\n address indexed depositor,\\n address updatedRecipient,\\n bytes updatedMessage,\\n bytes depositorSignature\\n );\\n\\n event FilledV3Relay(\\n address inputToken,\\n address outputToken,\\n uint256 inputAmount,\\n uint256 outputAmount,\\n uint256 repaymentChainId,\\n uint256 indexed originChainId,\\n uint32 indexed depositId,\\n uint32 fillDeadline,\\n uint32 exclusivityDeadline,\\n address exclusiveRelayer,\\n address indexed relayer,\\n address depositor,\\n address recipient,\\n bytes message,\\n V3RelayExecutionEventInfo relayExecutionInfo\\n );\\n\\n event RequestedV3SlowFill(\\n address inputToken,\\n address outputToken,\\n uint256 inputAmount,\\n uint256 outputAmount,\\n uint256 indexed originChainId,\\n uint32 indexed depositId,\\n uint32 fillDeadline,\\n uint32 exclusivityDeadline,\\n address exclusiveRelayer,\\n address depositor,\\n address recipient,\\n bytes message\\n );\\n\\n /**************************************\\n * FUNCTIONS *\\n **************************************/\\n\\n function depositV3(\\n address depositor,\\n address recipient,\\n address inputToken,\\n address outputToken,\\n uint256 inputAmount,\\n uint256 outputAmount,\\n uint256 destinationChainId,\\n address exclusiveRelayer,\\n uint32 quoteTimestamp,\\n uint32 fillDeadline,\\n uint32 exclusivityDeadline,\\n bytes calldata message\\n ) external payable;\\n\\n function depositV3Now(\\n address depositor,\\n address recipient,\\n address inputToken,\\n address outputToken,\\n uint256 inputAmount,\\n uint256 outputAmount,\\n uint256 destinationChainId,\\n address exclusiveRelayer,\\n uint32 fillDeadlineOffset,\\n uint32 exclusivityDeadline,\\n bytes calldata message\\n ) external payable;\\n\\n function speedUpV3Deposit(\\n address depositor,\\n uint32 depositId,\\n uint256 updatedOutputAmount,\\n address updatedRecipient,\\n bytes calldata updatedMessage,\\n bytes calldata depositorSignature\\n ) external;\\n\\n function fillV3Relay(V3RelayData calldata relayData, uint256 repaymentChainId) external;\\n\\n function fillV3RelayWithUpdatedDeposit(\\n V3RelayData calldata relayData,\\n uint256 repaymentChainId,\\n uint256 updatedOutputAmount,\\n address updatedRecipient,\\n bytes calldata updatedMessage,\\n bytes calldata depositorSignature\\n ) external;\\n\\n function requestV3SlowFill(V3RelayData calldata relayData) external;\\n\\n function executeV3SlowRelayLeaf(\\n V3SlowFill calldata slowFillLeaf,\\n uint32 rootBundleId,\\n bytes32[] calldata proof\\n ) external;\\n\\n /**************************************\\n * ERRORS *\\n **************************************/\\n\\n error DisabledRoute();\\n error InvalidQuoteTimestamp();\\n error InvalidFillDeadline();\\n error InvalidExclusiveRelayer();\\n error InvalidExclusivityDeadline();\\n error MsgValueDoesNotMatchInputAmount();\\n error NotExclusiveRelayer();\\n error NoSlowFillsInExclusivityWindow();\\n error RelayFilled();\\n error InvalidSlowFillRequest();\\n error ExpiredFillDeadline();\\n error InvalidMerkleProof();\\n error InvalidChainId();\\n error InvalidMerkleLeaf();\\n error ClaimedMerkleLeaf();\\n error InvalidPayoutAdjustmentPct();\\n}\\n\",\"keccak256\":\"0x374b7e9cb8afbcaec69cdbcde480676b5d927db84c7f38221331d1226af68d9d\",\"license\":\"BUSL-1.1\"}},\"version\":1}", + "bytecode": "0x60808060405234610016576103a4908161001c8239f35b600080fdfe600436101561000d57600080fd5b6000803560e01c63902e949c1461002357600080fd5b6101607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261036b5773ffffffffffffffffffffffffffffffffffffffff6004358181168103610367576024359082821682036103635760443591838316830361035f5760c435848116810361035b5760e4359063ffffffff928383168303610357576101043590848216820361035357610124359385851685036103225767ffffffffffffffff610144351161032257366023610144350112156103225767ffffffffffffffff6101443560040135116103265767ffffffffffffffff6004610144350135601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f0116608090810191821191101761032657608060046101443590810135601f81017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f011683016040529182905236910160240111610322576101443560048101359060240160a03760a06004610144350135018a90526064353403610322578887163b15610322578887163b1561032257918589979593888296818e9c60409e9b979e519e8f9d8e917f7b9392320000000000000000000000000000000000000000000000000000000083523360048401521690602401521660448c01528b60648c015260643560848c015260843560a48c015260a43560c48c01521660e48a01521661010488015216610124860152166101448401526101648301610180905260805180610184850152845b8181106103075750908391827fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f6101a49389858286010152011681010301923491165af180156102fc576102ba575080f35b67ffffffffffffffff81116102cf5760405280f35b6024827f4e487b710000000000000000000000000000000000000000000000000000000081526041600452fd5b6040513d84823e3d90fd5b60a08101518782016101a40152879550869450602001610266565b8980fd5b60248a7f4e487b710000000000000000000000000000000000000000000000000000000081526041600452fd5b8880fd5b8780fd5b8580fd5b8480fd5b8380fd5b8280fd5b80fdfea26469706673582212201ceff237e6adbd0d3f92e892f7f3f51306c23eac5f7e3f896c2c723d9e5be3a664736f6c63430008130033", + "deployedBytecode": "0x600436101561000d57600080fd5b6000803560e01c63902e949c1461002357600080fd5b6101607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261036b5773ffffffffffffffffffffffffffffffffffffffff6004358181168103610367576024359082821682036103635760443591838316830361035f5760c435848116810361035b5760e4359063ffffffff928383168303610357576101043590848216820361035357610124359385851685036103225767ffffffffffffffff610144351161032257366023610144350112156103225767ffffffffffffffff6101443560040135116103265767ffffffffffffffff6004610144350135601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f0116608090810191821191101761032657608060046101443590810135601f81017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f011683016040529182905236910160240111610322576101443560048101359060240160a03760a06004610144350135018a90526064353403610322578887163b15610322578887163b1561032257918589979593888296818e9c60409e9b979e519e8f9d8e917f7b9392320000000000000000000000000000000000000000000000000000000083523360048401521690602401521660448c01528b60648c015260643560848c015260843560a48c015260a43560c48c01521660e48a01521661010488015216610124860152166101448401526101648301610180905260805180610184850152845b8181106103075750908391827fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f6101a49389858286010152011681010301923491165af180156102fc576102ba575080f35b67ffffffffffffffff81116102cf5760405280f35b6024827f4e487b710000000000000000000000000000000000000000000000000000000081526041600452fd5b6040513d84823e3d90fd5b60a08101518782016101a40152879550869450602001610266565b8980fd5b60248a7f4e487b710000000000000000000000000000000000000000000000000000000081526041600452fd5b8880fd5b8780fd5b8580fd5b8480fd5b8380fd5b8280fd5b80fdfea26469706673582212201ceff237e6adbd0d3f92e892f7f3f51306c23eac5f7e3f896c2c723d9e5be3a664736f6c63430008130033", "devdoc": { + "custom:security-contact": "bugs@across.to", "details": "This contract must be deployed via Create2 to the same address on all chains. That way, an errant transaction sent to the wrong chain will be blocked by this contract rather than hitting a dead address. This means that this contract will not work to protect chains, like zkSync, where Create2 address derivations don't match other chains. Source: https://era.zksync.io/docs/reference/architecture/differences-with-ethereum.html#create-create2", "kind": "dev", "methods": { - "deposit(address,address,address,uint256,uint256,int64,uint32,bytes,uint256)": { + "deposit(address,address,address,uint256,uint256,uint256,address,uint32,uint32,uint32,bytes)": { "details": "Protects the caller from losing their ETH (or other native token) by reverting if the SpokePool address they intended to call does not exist on this chain. Because this contract can be deployed at the same address everywhere callers should be protected even if the transaction is submitted to an unintended network. This contract should only be used for native token deposits, as this problem only exists for native tokens.", "params": { - "amount": "Amount of tokens to deposit. Will be amount of tokens to receive less fees.", "destinationChainId": "Denotes network where user will receive funds from SpokePool by a relayer.", - "maxCount": "used to protect the depositor from frontrunning to guarantee their quote remains valid. Note: this is intended to be used to pass along instructions for how a contract should use or allocate the tokens.", + "exclusiveRelayer": "Address of the relayer who has exclusive rights to fill this deposit. Can be set to 0x0 if no exclusivity period is desired. If so, then must set exclusivityDeadline to 0.", + "exclusivityDeadline": "Timestamp after which any relayer can fill this deposit. Must set to 0 if exclusiveRelayer is set to 0x0, and vice versa.", + "fillDeadline": "Timestamp after which this deposit can no longer be filled.", + "inputAmount": "Amount of tokens to deposit.", + "inputToken": "Token to lock into this contract to initiate deposit.", "message": "Arbitrary data that can be used to pass additional information to the recipient along with the tokens. Note: this is intended to be used to pass along instructions for how a contract should use or allocate the tokens.", - "originToken": "Token to lock into this contract to initiate deposit.", + "outputAmount": "Amount of tokens to receive on destination chain.", "quoteTimestamp": "Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid to LP pool on HubPool.", "recipient": "Address to receive funds at on destination chain.", - "relayerFeePct": "% of deposit amount taken out to incentivize a fast relayer.", "spokePool": "Address of the SpokePool contract that the user is intending to call." } } @@ -101,7 +114,7 @@ "userdoc": { "kind": "user", "methods": { - "deposit(address,address,address,uint256,uint256,int64,uint32,bytes,uint256)": { + "deposit(address,address,address,uint256,uint256,uint256,address,uint32,uint32,uint32,bytes)": { "notice": "Passthrough function to `depositV3()` on the SpokePool contract." } }, diff --git a/deployments/scroll/solcInputs/1a67233dfe969c05446730f26ab1d2c8.json b/deployments/scroll/solcInputs/1a67233dfe969c05446730f26ab1d2c8.json new file mode 100644 index 000000000..96daeb1aa --- /dev/null +++ b/deployments/scroll/solcInputs/1a67233dfe969c05446730f26ab1d2c8.json @@ -0,0 +1,43 @@ +{ + "language": "Solidity", + "sources": { + "@openzeppelin/contracts/utils/Address.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (utils/Address.sol)\n\npragma solidity ^0.8.1;\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 * Furthermore, `isContract` will also return true if the target contract within\n * the same transaction is already scheduled for destruction by `SELFDESTRUCT`,\n * which only has an effect at the end of a transaction.\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 > 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://consensys.net/diligence/blog/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.8.0/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n require(address(this).balance >= amount, \"Address: insufficient balance\");\n\n (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 functionCallWithValue(target, data, 0, \"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(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n return functionCallWithValue(target, data, value, \"Address: low-level call with value failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\n * with `errorMessage` as a fallback revert reason when `target` reverts.\n *\n * _Available since v3.1._\n */\n function functionCallWithValue(\n address target,\n bytes memory data,\n uint256 value,\n string memory errorMessage\n ) internal returns (bytes memory) {\n require(address(this).balance >= value, \"Address: insufficient balance for call\");\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, 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 (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, 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 (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata, errorMessage);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling\n * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.\n *\n * _Available since v4.8._\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata,\n string memory errorMessage\n ) internal view returns (bytes memory) {\n if (success) {\n if (returndata.length == 0) {\n // only check isContract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n require(isContract(target), \"Address: call to non-contract\");\n }\n return returndata;\n } else {\n _revert(returndata, errorMessage);\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the\n * revert reason or 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 _revert(returndata, errorMessage);\n }\n }\n\n function _revert(bytes memory returndata, string memory errorMessage) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length > 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert(errorMessage);\n }\n }\n}\n" + }, + "contracts/interfaces/V3SpokePoolInterface.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n// Contains structs and functions used by SpokePool contracts to facilitate universal settlement.\ninterface V3SpokePoolInterface {\n /**************************************\n * ENUMS *\n **************************************/\n\n // Fill status tracks on-chain state of deposit, uniquely identified by relayHash.\n enum FillStatus {\n Unfilled,\n RequestedSlowFill,\n Filled\n }\n // Fill type is emitted in the FilledRelay event to assist Dataworker with determining which types of\n // fills to refund (e.g. only fast fills) and whether a fast fill created a sow fill excess.\n enum FillType {\n FastFill,\n // Fast fills are normal fills that do not replace a slow fill request.\n ReplacedSlowFill,\n // Replaced slow fills are fast fills that replace a slow fill request. This type is used by the Dataworker\n // to know when to send excess funds from the SpokePool to the HubPool because they can no longer be used\n // for a slow fill execution.\n SlowFill\n // Slow fills are requested via requestSlowFill and executed by executeSlowRelayLeaf after a bundle containing\n // the slow fill is validated.\n }\n\n /**************************************\n * STRUCTS *\n **************************************/\n\n // This struct represents the data to fully specify a **unique** relay submitted on this chain.\n // This data is hashed with the chainId() and saved by the SpokePool to prevent collisions and protect against\n // replay attacks on other chains. If any portion of this data differs, the relay is considered to be\n // completely distinct.\n struct V3RelayData {\n // The address that made the deposit on the origin chain.\n address depositor;\n // The recipient address on the destination chain.\n address recipient;\n // This is the exclusive relayer who can fill the deposit before the exclusivity deadline.\n address exclusiveRelayer;\n // Token that is deposited on origin chain by depositor.\n address inputToken;\n // Token that is received on destination chain by recipient.\n address outputToken;\n // The amount of input token deposited by depositor.\n uint256 inputAmount;\n // The amount of output token to be received by recipient.\n uint256 outputAmount;\n // Origin chain id.\n uint256 originChainId;\n // The id uniquely identifying this deposit on the origin chain.\n uint32 depositId;\n // The timestamp on the destination chain after which this deposit can no longer be filled.\n uint32 fillDeadline;\n // The timestamp on the destination chain after which any relayer can fill the deposit.\n uint32 exclusivityDeadline;\n // Data that is forwarded to the recipient.\n bytes message;\n }\n\n // Contains parameters passed in by someone who wants to execute a slow relay leaf.\n struct V3SlowFill {\n V3RelayData relayData;\n uint256 chainId;\n uint256 updatedOutputAmount;\n }\n\n // Contains information about a relay to be sent along with additional information that is not unique to the\n // relay itself but is required to know how to process the relay. For example, \"updatedX\" fields can be used\n // by the relayer to modify fields of the relay with the depositor's permission, and \"repaymentChainId\" is specified\n // by the relayer to determine where to take a relayer refund, but doesn't affect the uniqueness of the relay.\n struct V3RelayExecutionParams {\n V3RelayData relay;\n bytes32 relayHash;\n uint256 updatedOutputAmount;\n address updatedRecipient;\n bytes updatedMessage;\n uint256 repaymentChainId;\n }\n\n // Packs together parameters emitted in FilledV3Relay because there are too many emitted otherwise.\n // Similar to V3RelayExecutionParams, these parameters are not used to uniquely identify the deposit being\n // filled so they don't have to be unpacked by all clients.\n struct V3RelayExecutionEventInfo {\n address updatedRecipient;\n bytes updatedMessage;\n uint256 updatedOutputAmount;\n FillType fillType;\n }\n\n /**************************************\n * EVENTS *\n **************************************/\n\n event V3FundsDeposited(\n address inputToken,\n address outputToken,\n uint256 inputAmount,\n uint256 outputAmount,\n uint256 indexed destinationChainId,\n uint32 indexed depositId,\n uint32 quoteTimestamp,\n uint32 fillDeadline,\n uint32 exclusivityDeadline,\n address indexed depositor,\n address recipient,\n address exclusiveRelayer,\n bytes message\n );\n\n event RequestedSpeedUpV3Deposit(\n uint256 updatedOutputAmount,\n uint32 indexed depositId,\n address indexed depositor,\n address updatedRecipient,\n bytes updatedMessage,\n bytes depositorSignature\n );\n\n event FilledV3Relay(\n address inputToken,\n address outputToken,\n uint256 inputAmount,\n uint256 outputAmount,\n uint256 repaymentChainId,\n uint256 indexed originChainId,\n uint32 indexed depositId,\n uint32 fillDeadline,\n uint32 exclusivityDeadline,\n address exclusiveRelayer,\n address indexed relayer,\n address depositor,\n address recipient,\n bytes message,\n V3RelayExecutionEventInfo relayExecutionInfo\n );\n\n event RequestedV3SlowFill(\n address inputToken,\n address outputToken,\n uint256 inputAmount,\n uint256 outputAmount,\n uint256 indexed originChainId,\n uint32 indexed depositId,\n uint32 fillDeadline,\n uint32 exclusivityDeadline,\n address exclusiveRelayer,\n address depositor,\n address recipient,\n bytes message\n );\n\n /**************************************\n * FUNCTIONS *\n **************************************/\n\n function depositV3(\n address depositor,\n address recipient,\n address inputToken,\n address outputToken,\n uint256 inputAmount,\n uint256 outputAmount,\n uint256 destinationChainId,\n address exclusiveRelayer,\n uint32 quoteTimestamp,\n uint32 fillDeadline,\n uint32 exclusivityDeadline,\n bytes calldata message\n ) external payable;\n\n function depositV3Now(\n address depositor,\n address recipient,\n address inputToken,\n address outputToken,\n uint256 inputAmount,\n uint256 outputAmount,\n uint256 destinationChainId,\n address exclusiveRelayer,\n uint32 fillDeadlineOffset,\n uint32 exclusivityDeadline,\n bytes calldata message\n ) external payable;\n\n function speedUpV3Deposit(\n address depositor,\n uint32 depositId,\n uint256 updatedOutputAmount,\n address updatedRecipient,\n bytes calldata updatedMessage,\n bytes calldata depositorSignature\n ) external;\n\n function fillV3Relay(V3RelayData calldata relayData, uint256 repaymentChainId) external;\n\n function fillV3RelayWithUpdatedDeposit(\n V3RelayData calldata relayData,\n uint256 repaymentChainId,\n uint256 updatedOutputAmount,\n address updatedRecipient,\n bytes calldata updatedMessage,\n bytes calldata depositorSignature\n ) external;\n\n function requestV3SlowFill(V3RelayData calldata relayData) external;\n\n function executeV3SlowRelayLeaf(\n V3SlowFill calldata slowFillLeaf,\n uint32 rootBundleId,\n bytes32[] calldata proof\n ) external;\n\n /**************************************\n * ERRORS *\n **************************************/\n\n error DisabledRoute();\n error InvalidQuoteTimestamp();\n error InvalidFillDeadline();\n error InvalidExclusiveRelayer();\n error InvalidExclusivityDeadline();\n error MsgValueDoesNotMatchInputAmount();\n error NotExclusiveRelayer();\n error NoSlowFillsInExclusivityWindow();\n error RelayFilled();\n error InvalidSlowFillRequest();\n error ExpiredFillDeadline();\n error InvalidMerkleProof();\n error InvalidChainId();\n error InvalidMerkleLeaf();\n error ClaimedMerkleLeaf();\n error InvalidPayoutAdjustmentPct();\n}\n" + }, + "contracts/SpokePoolVerifier.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/utils/Address.sol\";\nimport \"./interfaces/V3SpokePoolInterface.sol\";\n\n/**\n * @notice SpokePoolVerifier is a contract that verifies that the SpokePool exists on this chain before sending ETH to it.\n * @dev This contract must be deployed via Create2 to the same address on all chains. That way, an errant transaction sent\n * to the wrong chain will be blocked by this contract rather than hitting a dead address. This means that this contract\n * will not work to protect chains, like zkSync, where Create2 address derivations don't match other chains.\n * Source: https://era.zksync.io/docs/reference/architecture/differences-with-ethereum.html#create-create2\n * @custom:security-contact bugs@across.to\n */\ncontract SpokePoolVerifier {\n using Address for address;\n\n /**\n * @notice Passthrough function to `depositV3()` on the SpokePool contract.\n * @dev Protects the caller from losing their ETH (or other native token) by reverting if the SpokePool address\n * they intended to call does not exist on this chain. Because this contract can be deployed at the same address\n * everywhere callers should be protected even if the transaction is submitted to an unintended network.\n * This contract should only be used for native token deposits, as this problem only exists for native tokens.\n * @param spokePool Address of the SpokePool contract that the user is intending to call.\n * @param recipient Address to receive funds at on destination chain.\n * @param inputToken Token to lock into this contract to initiate deposit.\n * @param inputAmount Amount of tokens to deposit.\n * @param outputAmount Amount of tokens to receive on destination chain.\n * @param destinationChainId Denotes network where user will receive funds from SpokePool by a relayer.\n * @param quoteTimestamp Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid\n * to LP pool on HubPool.\n * @param message Arbitrary data that can be used to pass additional information to the recipient along with the tokens.\n * Note: this is intended to be used to pass along instructions for how a contract should use or allocate the tokens.\n * @param exclusiveRelayer Address of the relayer who has exclusive rights to fill this deposit. Can be set to\n * 0x0 if no exclusivity period is desired. If so, then must set exclusivityDeadline to 0.\n * @param exclusivityDeadline Timestamp after which any relayer can fill this deposit. Must set\n * to 0 if exclusiveRelayer is set to 0x0, and vice versa.\n * @param fillDeadline Timestamp after which this deposit can no longer be filled.\n */\n function deposit(\n V3SpokePoolInterface spokePool,\n address recipient,\n address inputToken,\n uint256 inputAmount,\n uint256 outputAmount,\n uint256 destinationChainId,\n uint32 quoteTimestamp,\n bytes memory message,\n address exclusiveRelayer,\n uint32 exclusivityDeadline,\n uint32 fillDeadline\n ) external payable {\n require(msg.value == inputAmount, \"msg.value != amount\");\n require(address(spokePool).isContract(), \"spokePool is not a contract\");\n // Set msg.sender as the depositor so that msg.sender can speed up the deposit.\n spokePool.depositV3{ value: msg.value }(\n msg.sender,\n recipient,\n inputToken,\n // @dev Setting outputToken to 0x0 to instruct fillers to use the equivalent token\n // as the originToken on the destination chain.\n address(0),\n inputAmount,\n outputAmount,\n destinationChainId,\n exclusiveRelayer,\n quoteTimestamp,\n fillDeadline,\n exclusivityDeadline,\n message\n );\n }\n}\n" + } + }, + "settings": { + "optimizer": { + "enabled": true, + "runs": 1000000 + }, + "viaIR": true, + "debug": { + "revertStrings": "strip" + }, + "outputSelection": { + "*": { + "*": [ + "abi", + "evm.bytecode", + "evm.deployedBytecode", + "evm.methodIdentifiers", + "metadata", + "devdoc", + "userdoc", + "storageLayout", + "evm.gasEstimates" + ], + "": ["ast"] + } + }, + "metadata": { + "useLiteralContent": true + } + } +} diff --git a/deployments/scroll/solcInputs/783274f805324492b21545b62eb0dbfe.json b/deployments/scroll/solcInputs/783274f805324492b21545b62eb0dbfe.json new file mode 100644 index 000000000..4bcffc07b --- /dev/null +++ b/deployments/scroll/solcInputs/783274f805324492b21545b62eb0dbfe.json @@ -0,0 +1,43 @@ +{ + "language": "Solidity", + "sources": { + "@openzeppelin/contracts/utils/Address.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (utils/Address.sol)\n\npragma solidity ^0.8.1;\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 * Furthermore, `isContract` will also return true if the target contract within\n * the same transaction is already scheduled for destruction by `SELFDESTRUCT`,\n * which only has an effect at the end of a transaction.\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 > 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://consensys.net/diligence/blog/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.8.0/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n require(address(this).balance >= amount, \"Address: insufficient balance\");\n\n (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 functionCallWithValue(target, data, 0, \"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(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n return functionCallWithValue(target, data, value, \"Address: low-level call with value failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\n * with `errorMessage` as a fallback revert reason when `target` reverts.\n *\n * _Available since v3.1._\n */\n function functionCallWithValue(\n address target,\n bytes memory data,\n uint256 value,\n string memory errorMessage\n ) internal returns (bytes memory) {\n require(address(this).balance >= value, \"Address: insufficient balance for call\");\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, 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 (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, 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 (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata, errorMessage);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling\n * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.\n *\n * _Available since v4.8._\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata,\n string memory errorMessage\n ) internal view returns (bytes memory) {\n if (success) {\n if (returndata.length == 0) {\n // only check isContract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n require(isContract(target), \"Address: call to non-contract\");\n }\n return returndata;\n } else {\n _revert(returndata, errorMessage);\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the\n * revert reason or 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 _revert(returndata, errorMessage);\n }\n }\n\n function _revert(bytes memory returndata, string memory errorMessage) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length > 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert(errorMessage);\n }\n }\n}\n" + }, + "contracts/interfaces/V3SpokePoolInterface.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n// Contains structs and functions used by SpokePool contracts to facilitate universal settlement.\ninterface V3SpokePoolInterface {\n /**************************************\n * ENUMS *\n **************************************/\n\n // Fill status tracks on-chain state of deposit, uniquely identified by relayHash.\n enum FillStatus {\n Unfilled,\n RequestedSlowFill,\n Filled\n }\n // Fill type is emitted in the FilledRelay event to assist Dataworker with determining which types of\n // fills to refund (e.g. only fast fills) and whether a fast fill created a sow fill excess.\n enum FillType {\n FastFill,\n // Fast fills are normal fills that do not replace a slow fill request.\n ReplacedSlowFill,\n // Replaced slow fills are fast fills that replace a slow fill request. This type is used by the Dataworker\n // to know when to send excess funds from the SpokePool to the HubPool because they can no longer be used\n // for a slow fill execution.\n SlowFill\n // Slow fills are requested via requestSlowFill and executed by executeSlowRelayLeaf after a bundle containing\n // the slow fill is validated.\n }\n\n /**************************************\n * STRUCTS *\n **************************************/\n\n // This struct represents the data to fully specify a **unique** relay submitted on this chain.\n // This data is hashed with the chainId() and saved by the SpokePool to prevent collisions and protect against\n // replay attacks on other chains. If any portion of this data differs, the relay is considered to be\n // completely distinct.\n struct V3RelayData {\n // The address that made the deposit on the origin chain.\n address depositor;\n // The recipient address on the destination chain.\n address recipient;\n // This is the exclusive relayer who can fill the deposit before the exclusivity deadline.\n address exclusiveRelayer;\n // Token that is deposited on origin chain by depositor.\n address inputToken;\n // Token that is received on destination chain by recipient.\n address outputToken;\n // The amount of input token deposited by depositor.\n uint256 inputAmount;\n // The amount of output token to be received by recipient.\n uint256 outputAmount;\n // Origin chain id.\n uint256 originChainId;\n // The id uniquely identifying this deposit on the origin chain.\n uint32 depositId;\n // The timestamp on the destination chain after which this deposit can no longer be filled.\n uint32 fillDeadline;\n // The timestamp on the destination chain after which any relayer can fill the deposit.\n uint32 exclusivityDeadline;\n // Data that is forwarded to the recipient.\n bytes message;\n }\n\n // Contains parameters passed in by someone who wants to execute a slow relay leaf.\n struct V3SlowFill {\n V3RelayData relayData;\n uint256 chainId;\n uint256 updatedOutputAmount;\n }\n\n // Contains information about a relay to be sent along with additional information that is not unique to the\n // relay itself but is required to know how to process the relay. For example, \"updatedX\" fields can be used\n // by the relayer to modify fields of the relay with the depositor's permission, and \"repaymentChainId\" is specified\n // by the relayer to determine where to take a relayer refund, but doesn't affect the uniqueness of the relay.\n struct V3RelayExecutionParams {\n V3RelayData relay;\n bytes32 relayHash;\n uint256 updatedOutputAmount;\n address updatedRecipient;\n bytes updatedMessage;\n uint256 repaymentChainId;\n }\n\n // Packs together parameters emitted in FilledV3Relay because there are too many emitted otherwise.\n // Similar to V3RelayExecutionParams, these parameters are not used to uniquely identify the deposit being\n // filled so they don't have to be unpacked by all clients.\n struct V3RelayExecutionEventInfo {\n address updatedRecipient;\n bytes updatedMessage;\n uint256 updatedOutputAmount;\n FillType fillType;\n }\n\n /**************************************\n * EVENTS *\n **************************************/\n\n event V3FundsDeposited(\n address inputToken,\n address outputToken,\n uint256 inputAmount,\n uint256 outputAmount,\n uint256 indexed destinationChainId,\n uint32 indexed depositId,\n uint32 quoteTimestamp,\n uint32 fillDeadline,\n uint32 exclusivityDeadline,\n address indexed depositor,\n address recipient,\n address exclusiveRelayer,\n bytes message\n );\n\n event RequestedSpeedUpV3Deposit(\n uint256 updatedOutputAmount,\n uint32 indexed depositId,\n address indexed depositor,\n address updatedRecipient,\n bytes updatedMessage,\n bytes depositorSignature\n );\n\n event FilledV3Relay(\n address inputToken,\n address outputToken,\n uint256 inputAmount,\n uint256 outputAmount,\n uint256 repaymentChainId,\n uint256 indexed originChainId,\n uint32 indexed depositId,\n uint32 fillDeadline,\n uint32 exclusivityDeadline,\n address exclusiveRelayer,\n address indexed relayer,\n address depositor,\n address recipient,\n bytes message,\n V3RelayExecutionEventInfo relayExecutionInfo\n );\n\n event RequestedV3SlowFill(\n address inputToken,\n address outputToken,\n uint256 inputAmount,\n uint256 outputAmount,\n uint256 indexed originChainId,\n uint32 indexed depositId,\n uint32 fillDeadline,\n uint32 exclusivityDeadline,\n address exclusiveRelayer,\n address depositor,\n address recipient,\n bytes message\n );\n\n /**************************************\n * FUNCTIONS *\n **************************************/\n\n function depositV3(\n address depositor,\n address recipient,\n address inputToken,\n address outputToken,\n uint256 inputAmount,\n uint256 outputAmount,\n uint256 destinationChainId,\n address exclusiveRelayer,\n uint32 quoteTimestamp,\n uint32 fillDeadline,\n uint32 exclusivityDeadline,\n bytes calldata message\n ) external payable;\n\n function depositV3Now(\n address depositor,\n address recipient,\n address inputToken,\n address outputToken,\n uint256 inputAmount,\n uint256 outputAmount,\n uint256 destinationChainId,\n address exclusiveRelayer,\n uint32 fillDeadlineOffset,\n uint32 exclusivityDeadline,\n bytes calldata message\n ) external payable;\n\n function speedUpV3Deposit(\n address depositor,\n uint32 depositId,\n uint256 updatedOutputAmount,\n address updatedRecipient,\n bytes calldata updatedMessage,\n bytes calldata depositorSignature\n ) external;\n\n function fillV3Relay(V3RelayData calldata relayData, uint256 repaymentChainId) external;\n\n function fillV3RelayWithUpdatedDeposit(\n V3RelayData calldata relayData,\n uint256 repaymentChainId,\n uint256 updatedOutputAmount,\n address updatedRecipient,\n bytes calldata updatedMessage,\n bytes calldata depositorSignature\n ) external;\n\n function requestV3SlowFill(V3RelayData calldata relayData) external;\n\n function executeV3SlowRelayLeaf(\n V3SlowFill calldata slowFillLeaf,\n uint32 rootBundleId,\n bytes32[] calldata proof\n ) external;\n\n /**************************************\n * ERRORS *\n **************************************/\n\n error DisabledRoute();\n error InvalidQuoteTimestamp();\n error InvalidFillDeadline();\n error InvalidExclusiveRelayer();\n error InvalidExclusivityDeadline();\n error MsgValueDoesNotMatchInputAmount();\n error NotExclusiveRelayer();\n error NoSlowFillsInExclusivityWindow();\n error RelayFilled();\n error InvalidSlowFillRequest();\n error ExpiredFillDeadline();\n error InvalidMerkleProof();\n error InvalidChainId();\n error InvalidMerkleLeaf();\n error ClaimedMerkleLeaf();\n error InvalidPayoutAdjustmentPct();\n}\n" + }, + "contracts/SpokePoolVerifier.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/utils/Address.sol\";\nimport \"./interfaces/V3SpokePoolInterface.sol\";\n\n/**\n * @notice SpokePoolVerifier is a contract that verifies that the SpokePool exists on this chain before sending ETH to it.\n * @dev This contract must be deployed via Create2 to the same address on all chains. That way, an errant transaction sent\n * to the wrong chain will be blocked by this contract rather than hitting a dead address. This means that this contract\n * will not work to protect chains, like zkSync, where Create2 address derivations don't match other chains.\n * Source: https://era.zksync.io/docs/reference/architecture/differences-with-ethereum.html#create-create2\n * @custom:security-contact bugs@across.to\n */\ncontract SpokePoolVerifier {\n using Address for address;\n\n /**\n * @notice Passthrough function to `depositV3()` on the SpokePool contract.\n * @dev Protects the caller from losing their ETH (or other native token) by reverting if the SpokePool address\n * they intended to call does not exist on this chain. Because this contract can be deployed at the same address\n * everywhere callers should be protected even if the transaction is submitted to an unintended network.\n * This contract should only be used for native token deposits, as this problem only exists for native tokens.\n * @param spokePool Address of the SpokePool contract that the user is intending to call.\n * @param recipient Address to receive funds at on destination chain.\n * @param inputToken Token to lock into this contract to initiate deposit.\n * @param inputAmount Amount of tokens to deposit.\n * @param outputAmount Amount of tokens to receive on destination chain.\n * @param destinationChainId Denotes network where user will receive funds from SpokePool by a relayer.\n * @param quoteTimestamp Timestamp used by relayers to compute this deposit's realizedLPFeePct which is paid\n * to LP pool on HubPool.\n * @param message Arbitrary data that can be used to pass additional information to the recipient along with the tokens.\n * Note: this is intended to be used to pass along instructions for how a contract should use or allocate the tokens.\n * @param exclusiveRelayer Address of the relayer who has exclusive rights to fill this deposit. Can be set to\n * 0x0 if no exclusivity period is desired. If so, then must set exclusivityDeadline to 0.\n * @param exclusivityDeadline Timestamp after which any relayer can fill this deposit. Must set\n * to 0 if exclusiveRelayer is set to 0x0, and vice versa.\n * @param fillDeadline Timestamp after which this deposit can no longer be filled.\n */\n function deposit(\n V3SpokePoolInterface spokePool,\n address recipient,\n address inputToken,\n uint256 inputAmount,\n uint256 outputAmount,\n uint256 destinationChainId,\n address exclusiveRelayer,\n uint32 quoteTimestamp,\n uint32 fillDeadline,\n uint32 exclusivityDeadline,\n bytes memory message\n ) external payable {\n require(msg.value == inputAmount, \"msg.value != amount\");\n require(address(spokePool).isContract(), \"spokePool is not a contract\");\n // Set msg.sender as the depositor so that msg.sender can speed up the deposit.\n spokePool.depositV3{ value: msg.value }(\n msg.sender,\n recipient,\n inputToken,\n // @dev Setting outputToken to 0x0 to instruct fillers to use the equivalent token\n // as the originToken on the destination chain.\n address(0),\n inputAmount,\n outputAmount,\n destinationChainId,\n exclusiveRelayer,\n quoteTimestamp,\n fillDeadline,\n exclusivityDeadline,\n message\n );\n }\n}\n" + } + }, + "settings": { + "optimizer": { + "enabled": true, + "runs": 1000000 + }, + "viaIR": true, + "debug": { + "revertStrings": "strip" + }, + "outputSelection": { + "*": { + "*": [ + "abi", + "evm.bytecode", + "evm.deployedBytecode", + "evm.methodIdentifiers", + "metadata", + "devdoc", + "userdoc", + "storageLayout", + "evm.gasEstimates" + ], + "": ["ast"] + } + }, + "metadata": { + "useLiteralContent": true + } + } +} diff --git a/test/foundry/local/Blast_DaiRetriever.sol b/test/foundry/local/Blast_DaiRetriever.t.sol similarity index 100% rename from test/foundry/local/Blast_DaiRetriever.sol rename to test/foundry/local/Blast_DaiRetriever.t.sol diff --git a/test/foundry/local/SpokePoolVerifier.t.sol b/test/foundry/local/SpokePoolVerifier.t.sol new file mode 100644 index 000000000..6b770d056 --- /dev/null +++ b/test/foundry/local/SpokePoolVerifier.t.sol @@ -0,0 +1,157 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity ^0.8.0; + +import { Test } from "forge-std/Test.sol"; + +import { SpokePoolVerifier } from "../../../contracts/SpokePoolVerifier.sol"; +import { Ethereum_SpokePool } from "../../../contracts/Ethereum_SpokePool.sol"; +import { V3SpokePoolInterface } from "../../../contracts/interfaces/V3SpokePoolInterface.sol"; +import { WETH9 } from "../../../contracts/external/WETH9.sol"; +import { ERC20 } from "@openzeppelin/contracts/token/ERC20/ERC20.sol"; +import { ERC1967Proxy } from "@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol"; + +contract SpokePoolVerifierTest is Test { + Ethereum_SpokePool ethereumSpokePool; + SpokePoolVerifier spokePoolVerifier; + + ERC20 mockWETH; + ERC20 mockERC20; + + address depositor; + address owner; + + uint256 destinationChainId = 10; + uint256 mintAmount = 10**22; + uint256 depositAmount = 5 * (10**18); + uint32 fillDeadlineBuffer = 7200; + + function setUp() public { + mockWETH = ERC20(address(new WETH9())); + mockERC20 = new ERC20("ERC20", "ERC20"); + + depositor = vm.addr(1); + owner = vm.addr(2); + + vm.startPrank(owner); + Ethereum_SpokePool implementation = new Ethereum_SpokePool( + address(mockWETH), + fillDeadlineBuffer, + fillDeadlineBuffer + ); + address proxy = address( + new ERC1967Proxy(address(implementation), abi.encodeCall(Ethereum_SpokePool.initialize, (0, owner))) + ); + ethereumSpokePool = Ethereum_SpokePool(payable(proxy)); + ethereumSpokePool.setEnableRoute(address(mockWETH), destinationChainId, true); + ethereumSpokePool.setEnableRoute(address(mockERC20), destinationChainId, true); + spokePoolVerifier = new SpokePoolVerifier(); + vm.stopPrank(); + + deal(depositor, mintAmount); + deal(address(mockERC20), depositor, mintAmount, true); + vm.prank(depositor); + mockERC20.approve(address(ethereumSpokePool), mintAmount); + } + + function testInvalidMsgValue() public { + vm.startPrank(depositor); + + // Reverts if inputToken is WETH and msg.value is not equal to inputAmount + vm.expectRevert(SpokePoolVerifier.InvalidMsgValue.selector); + spokePoolVerifier.deposit{ value: 0 }( + ethereumSpokePool, // spokePool + depositor, // recipient + address(mockWETH), // inputToken + depositAmount, // inputAmount + depositAmount, // outputAmount + destinationChainId, // destinationChainId + address(0), // exclusiveRelayer + uint32(block.timestamp), // quoteTimestamp + uint32(block.timestamp) + fillDeadlineBuffer, // fillDeadline + 0, // exclusivityDeadline + bytes("") // message + ); + + // Reverts if msg.value matches inputAmount but inputToken is not WETH + vm.expectRevert(V3SpokePoolInterface.MsgValueDoesNotMatchInputAmount.selector); + spokePoolVerifier.deposit{ value: depositAmount }( + ethereumSpokePool, // spokePool + depositor, // recipient + address(mockERC20), // inputToken + depositAmount, // inputAmount + depositAmount, // outputAmount + destinationChainId, // destinationChainId + address(0), // exclusiveRelayer + uint32(block.timestamp), // quoteTimestamp + uint32(block.timestamp) + fillDeadlineBuffer, // fillDeadline + 0, // exclusivityDeadline + bytes("") // message + ); + + vm.stopPrank(); + } + + function testInvalidSpokePool() public { + vm.startPrank(depositor); + + // Reverts if spokePool is not a contract + vm.expectRevert(SpokePoolVerifier.InvalidSpokePool.selector); + spokePoolVerifier.deposit{ value: depositAmount }( + V3SpokePoolInterface(address(0)), // spokePool + depositor, // recipient + address(mockWETH), // inputToken + depositAmount, // inputAmount + depositAmount, // outputAmount + destinationChainId, // destinationChainId + address(0), // exclusiveRelayer + uint32(block.timestamp), // quoteTimestamp + uint32(block.timestamp) + fillDeadlineBuffer, // fillDeadline + 0, // exclusivityDeadline + bytes("") // message + ); + + vm.stopPrank(); + } + + function testSuccess() public { + vm.startPrank(depositor); + + // Deposits WETH + vm.expectCall( + address(ethereumSpokePool), // callee + depositAmount, // value + abi.encodeCall( // data + ethereumSpokePool.depositV3, + ( + depositor, + depositor, + address(mockWETH), + address(0), + depositAmount, + depositAmount, + destinationChainId, + address(0), + uint32(block.timestamp), + uint32(block.timestamp) + fillDeadlineBuffer, + 0, + bytes("") + ) + ) + ); + spokePoolVerifier.deposit{ value: depositAmount }( + ethereumSpokePool, // spokePool + depositor, // recipient + address(mockWETH), // inputToken + depositAmount, // inputAmount + depositAmount, // outputAmount + destinationChainId, // destinationChainId + address(0), // exclusiveRelayer + uint32(block.timestamp), // quoteTimestamp + uint32(block.timestamp) + fillDeadlineBuffer, // fillDeadline + 0, // exclusivityDeadline + bytes("") // message + ); + + vm.stopPrank(); + } +}